home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / ex_docmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-15  |  192.7 KB  |  8,910 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * ex_docmd.c: functions for executing an Ex command line.
  12.  */
  13.  
  14. #include "vim.h"
  15.  
  16. #ifdef HAVE_FCNTL_H
  17. # include <fcntl.h>        /* for chdir() */
  18. #endif
  19.  
  20. static int    quitmore = 0;
  21. static int    ex_pressedreturn = FALSE;
  22. #ifndef FEAT_PRINTER
  23. # define ex_hardcopy    ex_ni
  24. #endif
  25.  
  26. #ifdef FEAT_USR_CMDS
  27. typedef struct ucmd
  28. {
  29.     char_u    *uc_name;    /* The command name */
  30.     long_u    uc_argt;    /* The argument type */
  31.     char_u    *uc_rep;    /* The command's replacement string */
  32.     long    uc_def;        /* The default value for a range/count */
  33.     scid_T    uc_scriptID;    /* SID where the command was defined */
  34.     int        uc_compl;    /* completion type */
  35. } ucmd_T;
  36.  
  37. #define UC_BUFFER    1    /* -buffer: local to current buffer */
  38.  
  39. garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL};
  40.  
  41. #define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i])
  42. #define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
  43.  
  44. static void do_ucmd __ARGS((exarg_T *eap));
  45. static void ex_command __ARGS((exarg_T *eap));
  46. static void ex_comclear __ARGS((exarg_T *eap));
  47. static void ex_delcommand __ARGS((exarg_T *eap));
  48. # ifdef FEAT_CMDL_COMPL
  49. static char_u *get_user_command_name __ARGS((int idx));
  50. # endif
  51.  
  52. #else
  53. # define ex_command    ex_ni
  54. # define ex_comclear    ex_ni
  55. # define ex_delcommand    ex_ni
  56. #endif
  57.  
  58. #ifdef FEAT_EVAL
  59. static void free_cmdlines __ARGS((garray_T *gap));
  60. static char_u    *do_one_cmd __ARGS((char_u **, int, struct condstack *, char_u *(*getline)(int, void *, int), void *cookie));
  61. #else
  62. static char_u    *do_one_cmd __ARGS((char_u **, int, char_u *(*getline)(int, void *, int), void *cookie));
  63. static int    if_level = 0;        /* depth in :if */
  64. #endif
  65. static int    checkforcmd __ARGS((char_u **pp, char *cmd, int len));
  66. static char_u    *find_command __ARGS((exarg_T *eap, int *full));
  67.  
  68. static void    ex_abbreviate __ARGS((exarg_T *eap));
  69. static void    ex_map __ARGS((exarg_T *eap));
  70. static void    ex_unmap __ARGS((exarg_T *eap));
  71. static void    ex_mapclear __ARGS((exarg_T *eap));
  72. static void    ex_abclear __ARGS((exarg_T *eap));
  73. #ifndef FEAT_MENU
  74. # define ex_emenu        ex_ni
  75. # define ex_menu        ex_ni
  76. # define ex_menutranslate    ex_ni
  77. #endif
  78. #ifdef FEAT_AUTOCMD
  79. static void    ex_autocmd __ARGS((exarg_T *eap));
  80. static void    ex_doautocmd __ARGS((exarg_T *eap));
  81. #else
  82. # define ex_autocmd        ex_ni
  83. # define ex_doautocmd        ex_ni
  84. # define ex_doautoall        ex_ni
  85. #endif
  86. #ifdef FEAT_LISTCMDS
  87. static void    ex_bunload __ARGS((exarg_T *eap));
  88. static void    ex_buffer __ARGS((exarg_T *eap));
  89. static void    ex_bmodified __ARGS((exarg_T *eap));
  90. static void    ex_bnext __ARGS((exarg_T *eap));
  91. static void    ex_bprevious __ARGS((exarg_T *eap));
  92. static void    ex_brewind __ARGS((exarg_T *eap));
  93. static void    ex_blast __ARGS((exarg_T *eap));
  94. #else
  95. # define ex_bunload        ex_ni
  96. # define ex_buffer        ex_ni
  97. # define ex_bmodified        ex_ni
  98. # define ex_bnext        ex_ni
  99. # define ex_bprevious        ex_ni
  100. # define ex_brewind        ex_ni
  101. # define ex_blast        ex_ni
  102. # define buflist_list        ex_ni
  103. # define ex_checktime        ex_ni
  104. #endif
  105. #if !defined(FEAT_LISTCMDS) || !defined(FEAT_WINDOWS)
  106. # define ex_buffer_all        ex_ni
  107. #endif
  108. static char_u    *getargcmd __ARGS((char_u **));
  109. static char_u    *skip_cmd_arg __ARGS((char_u *p));
  110. static int    getargopt __ARGS((exarg_T *eap));
  111. #ifndef FEAT_QUICKFIX
  112. # define ex_make        ex_ni
  113. # define ex_cc            ex_ni
  114. # define ex_cnext        ex_ni
  115. # define ex_cfile        ex_ni
  116. # define qf_list        ex_ni
  117. # define qf_age            ex_ni
  118. #endif
  119. #if !defined(FEAT_QUICKFIX) || !defined(FEAT_WINDOWS)
  120. # define ex_cclose        ex_ni
  121. # define ex_copen        ex_ni
  122. # define ex_cwindow        ex_ni
  123. #endif
  124.  
  125. static int    check_more __ARGS((int, int));
  126. static linenr_T get_address __ARGS((char_u **, int skip));
  127. static char_u    *invalid_range __ARGS((exarg_T *eap));
  128. static void    correct_range __ARGS((exarg_T *eap));
  129. static char_u    *repl_cmdline __ARGS((exarg_T *eap, char_u *src, int srclen, char_u *repl, char_u **cmdlinep));
  130. static void    ex_highlight __ARGS((exarg_T *eap));
  131. static void    ex_colorscheme __ARGS((exarg_T *eap));
  132. static void    ex_quit __ARGS((exarg_T *eap));
  133. static void    ex_cquit __ARGS((exarg_T *eap));
  134. static void    ex_quit_all __ARGS((exarg_T *eap));
  135. #ifdef FEAT_WINDOWS
  136. static void    ex_close __ARGS((exarg_T *eap));
  137. static void    ex_win_close __ARGS((exarg_T *eap, win_T *win));
  138. static void    ex_only __ARGS((exarg_T *eap));
  139. static void    ex_all __ARGS((exarg_T *eap));
  140. static void    ex_resize __ARGS((exarg_T *eap));
  141. static void    ex_splitview __ARGS((exarg_T *eap));
  142. static void    ex_stag __ARGS((exarg_T *eap));
  143. #else
  144. # define ex_close        ex_ni
  145. # define ex_only        ex_ni
  146. # define ex_all            ex_ni
  147. # define ex_resize        ex_ni
  148. # define ex_splitview        ex_ni
  149. # define ex_stag        ex_ni
  150. #endif
  151. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  152. static void    ex_pclose __ARGS((exarg_T *eap));
  153. static void    ex_ptag __ARGS((exarg_T *eap));
  154. static void    ex_pedit __ARGS((exarg_T *eap));
  155. #else
  156. # define ex_pclose        ex_ni
  157. # define ex_ptag        ex_ni
  158. # define ex_pedit        ex_ni
  159. #endif
  160. static void    ex_hide __ARGS((exarg_T *eap));
  161. static void    ex_stop __ARGS((exarg_T *eap));
  162. static void    ex_exit __ARGS((exarg_T *eap));
  163. static void    ex_print __ARGS((exarg_T *eap));
  164. #ifdef FEAT_BYTEOFF
  165. static void    ex_goto __ARGS((exarg_T *eap));
  166. #else
  167. # define ex_goto        ex_ni
  168. #endif
  169. static void    ex_shell __ARGS((exarg_T *eap));
  170. static void    ex_preserve __ARGS((exarg_T *eap));
  171. static void    ex_recover __ARGS((exarg_T *eap));
  172. #ifndef FEAT_LISTCMDS
  173. # define ex_argedit        ex_ni
  174. # define ex_argadd        ex_ni
  175. # define ex_argdelete        ex_ni
  176. # define ex_listdo        ex_ni
  177. #endif
  178. static void    ex_mode __ARGS((exarg_T *eap));
  179. static void    ex_wrongmodifier __ARGS((exarg_T *eap));
  180. static void    ex_find __ARGS((exarg_T *eap));
  181. static void    ex_edit __ARGS((exarg_T *eap));
  182. #if !defined(FEAT_GUI) && !defined(FEAT_CLIENTSERVER)
  183. # define ex_drop        ex_ni
  184. #endif
  185. #ifndef FEAT_GUI
  186. # define ex_gui            ex_nogui
  187. static void    ex_nogui __ARGS((exarg_T *eap));
  188. #endif
  189. #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
  190. static void    ex_tearoff __ARGS((exarg_T *eap));
  191. #else
  192. # define ex_tearoff        ex_ni
  193. #endif
  194. #if defined(FEAT_GUI_MSWIN) && defined(FEAT_MENU)
  195. static void    ex_popup __ARGS((exarg_T *eap));
  196. #else
  197. # define ex_popup        ex_ni
  198. #endif
  199. #ifndef FEAT_GUI_MSWIN
  200. # define ex_simalt        ex_ni
  201. #endif
  202. #if !defined(FEAT_GUI_MSWIN) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
  203. # define gui_mch_find_dialog    ex_ni
  204. # define gui_mch_replace_dialog ex_ni
  205. #endif
  206. #ifndef FEAT_GUI_GTK
  207. # define ex_helpfind        ex_ni
  208. #endif
  209. #ifndef FEAT_CSCOPE
  210. # define do_cscope        ex_ni
  211. # define do_scscope        ex_ni
  212. # define do_cstag        ex_ni
  213. #endif
  214. #ifndef FEAT_SYN_HL
  215. # define ex_syntax        ex_ni
  216. #endif
  217. #ifndef FEAT_PERL
  218. # define ex_perl        ex_ni
  219. # define ex_perldo        ex_ni
  220. #endif
  221. #ifndef FEAT_PYTHON
  222. # define ex_python        ex_ni
  223. # define ex_pyfile        ex_ni
  224. #endif
  225. #ifndef FEAT_TCL
  226. # define ex_tcl            ex_ni
  227. # define ex_tcldo        ex_ni
  228. # define ex_tclfile        ex_ni
  229. #endif
  230. #ifndef FEAT_RUBY
  231. # define ex_ruby        ex_ni
  232. # define ex_rubydo        ex_ni
  233. # define ex_rubyfile        ex_ni
  234. #endif
  235. #ifndef FEAT_SNIFF
  236. # define ex_sniff        ex_ni
  237. #endif
  238. #ifndef FEAT_KEYMAP
  239. # define ex_loadkeymap        ex_ni
  240. #endif
  241. static void    ex_swapname __ARGS((exarg_T *eap));
  242. static void    ex_syncbind __ARGS((exarg_T *eap));
  243. static void    ex_read __ARGS((exarg_T *eap));
  244. static void    ex_cd __ARGS((exarg_T *eap));
  245. static void    ex_pwd __ARGS((exarg_T *eap));
  246. static void    ex_equal __ARGS((exarg_T *eap));
  247. static void    ex_sleep __ARGS((exarg_T *eap));
  248. static void    do_exmap __ARGS((exarg_T *eap, int isabbrev));
  249. static void    ex_winsize __ARGS((exarg_T *eap));
  250. #ifdef FEAT_WINDOWS
  251. static void    ex_wincmd __ARGS((exarg_T *eap));
  252. #else
  253. # define ex_wincmd        ex_ni
  254. #endif
  255. #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS)
  256. static void    ex_winpos __ARGS((exarg_T *eap));
  257. #else
  258. # define ex_winpos        ex_ni
  259. #endif
  260. static void    ex_operators __ARGS((exarg_T *eap));
  261. static void    ex_put __ARGS((exarg_T *eap));
  262. static void    ex_copymove __ARGS((exarg_T *eap));
  263. static void    ex_submagic __ARGS((exarg_T *eap));
  264. static void    ex_join __ARGS((exarg_T *eap));
  265. static void    ex_at __ARGS((exarg_T *eap));
  266. static void    ex_bang __ARGS((exarg_T *eap));
  267. static void    ex_undo __ARGS((exarg_T *eap));
  268. static void    ex_redo __ARGS((exarg_T *eap));
  269. static void    ex_redir __ARGS((exarg_T *eap));
  270. static void    ex_redraw __ARGS((exarg_T *eap));
  271. static void    close_redir __ARGS((void));
  272. static void    ex_mkrc __ARGS((exarg_T *eap));
  273. static void    ex_mark __ARGS((exarg_T *eap));
  274. #ifdef FEAT_USR_CMDS
  275. static char_u    *uc_fun_cmd __ARGS((void));
  276. #endif
  277. #ifdef FEAT_EX_EXTRA
  278. static void    ex_normal __ARGS((exarg_T *eap));
  279. static void    update_topline_cursor __ARGS((void));
  280. static void    ex_startinsert __ARGS((exarg_T *eap));
  281. #else
  282. # define ex_normal        ex_ni
  283. # define ex_align        ex_ni
  284. # define ex_retab        ex_ni
  285. # define ex_startinsert        ex_ni
  286. # define ex_helptags        ex_ni
  287. #endif
  288. #ifdef FEAT_FIND_ID
  289. static void    ex_checkpath __ARGS((exarg_T *eap));
  290. static void    ex_findpat __ARGS((exarg_T *eap));
  291. #else
  292. # define ex_findpat        ex_ni
  293. # define ex_checkpath        ex_ni
  294. #endif
  295. #if defined(FEAT_FIND_ID) && defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  296. static void    ex_psearch __ARGS((exarg_T *eap));
  297. #else
  298. # define ex_psearch        ex_ni
  299. #endif
  300. static void    ex_tag __ARGS((exarg_T *eap));
  301. static void    ex_tag_cmd __ARGS((exarg_T *eap, char_u *name));
  302. #ifdef FEAT_EVAL
  303. static void    ex_if __ARGS((exarg_T *eap));
  304. static void    ex_endif __ARGS((exarg_T *eap));
  305. static void    ex_else __ARGS((exarg_T *eap));
  306. static void    ex_while __ARGS((exarg_T *eap));
  307. static void    ex_continue __ARGS((exarg_T *eap));
  308. static void    ex_break __ARGS((exarg_T *eap));
  309. static void    ex_endwhile __ARGS((exarg_T *eap));
  310. static void    ex_endfunction __ARGS((exarg_T *eap));
  311. static int    has_while_cmd __ARGS((char_u *p));
  312. static int    did_endif = FALSE;    /* just had ":endif" */
  313. #else
  314. # define ex_scriptnames        ex_ni
  315. # define ex_finish        ex_ni
  316. # define ex_echo        ex_ni
  317. # define ex_echohl        ex_ni
  318. # define ex_execute        ex_ni
  319. # define ex_call        ex_ni
  320. # define ex_if            ex_ni
  321. # define ex_endif        ex_ni
  322. # define ex_else        ex_ni
  323. # define ex_while        ex_ni
  324. # define ex_continue        ex_ni
  325. # define ex_break        ex_ni
  326. # define ex_endwhile        ex_ni
  327. # define ex_endfunction        ex_ni
  328. # define ex_let            ex_ni
  329. # define ex_unlet        ex_ni
  330. # define ex_function        ex_ni
  331. # define ex_delfunction        ex_ni
  332. # define ex_return        ex_ni
  333. #endif
  334. static char_u    *arg_all __ARGS((void));
  335. #ifdef FEAT_SESSION
  336. static int    makeopens __ARGS((FILE *fd, char_u *dirnow));
  337. static int    put_view __ARGS((FILE *fd, win_T *wp, int add_edit, unsigned *flagp));
  338. static void    ex_loadview __ARGS((exarg_T *eap));
  339. static char_u    *get_view_file __ARGS((int c));
  340. #else
  341. # define ex_loadview        ex_ni
  342. #endif
  343. #ifndef FEAT_EVAL
  344. # define ex_compiler        ex_ni
  345. #endif
  346. #ifdef FEAT_VIMINFO
  347. static void    ex_viminfo __ARGS((exarg_T *eap));
  348. #else
  349. # define ex_viminfo        ex_ni
  350. #endif
  351. static void    ex_behave __ARGS((exarg_T *eap));
  352. #ifdef FEAT_AUTOCMD
  353. static void    ex_filetype __ARGS((exarg_T *eap));
  354. static void    ex_setfiletype  __ARGS((exarg_T *eap));
  355. #else
  356. # define ex_filetype        ex_ni
  357. # define ex_setfiletype        ex_ni
  358. #endif
  359. #ifndef FEAT_DIFF
  360. # define ex_diffpatch        ex_ni
  361. # define ex_diffgetput        ex_ni
  362. # define ex_diffsplit        ex_ni
  363. # define ex_diffthis        ex_ni
  364. # define ex_diffupdate        ex_ni
  365. #endif
  366. static void    ex_digraphs __ARGS((exarg_T *eap));
  367. static void    ex_set __ARGS((exarg_T *eap));
  368. #if !defined(FEAT_EVAL) || !defined(FEAT_AUTOCMD)
  369. # define ex_options        ex_ni
  370. #endif
  371. #ifdef FEAT_SEARCH_EXTRA
  372. static void    ex_nohlsearch __ARGS((exarg_T *eap));
  373. static void    ex_match __ARGS((exarg_T *eap));
  374. #else
  375. # define ex_nohlsearch        ex_ni
  376. # define ex_match        ex_ni
  377. #endif
  378. #ifdef FEAT_CRYPT
  379. static void    ex_X __ARGS((exarg_T *eap));
  380. #else
  381. # define ex_X            ex_ni
  382. #endif
  383. #ifdef FEAT_FOLDING
  384. static void    ex_fold __ARGS((exarg_T *eap));
  385. static void    ex_foldopen __ARGS((exarg_T *eap));
  386. static void    ex_folddo __ARGS((exarg_T *eap));
  387. #else
  388. # define ex_fold        ex_ni
  389. # define ex_foldopen        ex_ni
  390. # define ex_folddo        ex_ni
  391. #endif
  392. #if !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
  393.     && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)))
  394. # define ex_language        ex_ni
  395. #endif
  396. #ifndef FEAT_SIGNS
  397. # define ex_sign        ex_ni
  398. #endif
  399. #ifndef FEAT_SUN_WORKSHOP
  400. # define ex_wsverb        ex_ni
  401. #endif
  402.  
  403. #ifndef FEAT_EVAL
  404. # define ex_debug        ex_ni
  405. # define ex_breakadd        ex_ni
  406. # define ex_breakdel        ex_ni
  407. # define ex_breaklist        ex_ni
  408. #endif
  409.  
  410. #ifndef FEAT_CMDHIST
  411. # define ex_history        ex_ni
  412. #endif
  413. #ifndef FEAT_JUMPLIST
  414. # define ex_jumps        ex_ni
  415. #endif
  416.  
  417. /*
  418.  * Declare cmdnames[].
  419.  */
  420. #define DO_DECLARE_EXCMD
  421. #include "ex_cmds.h"
  422.  
  423. /*
  424.  * Table used to quickly search for a command, based on its first character.
  425.  */
  426. cmdidx_T cmdidxs[27] =
  427. {
  428.     CMD_append,
  429.     CMD_buffer,
  430.     CMD_change,
  431.     CMD_delete,
  432.     CMD_edit,
  433.     CMD_file,
  434.     CMD_global,
  435.     CMD_help,
  436.     CMD_insert,
  437.     CMD_join,
  438.     CMD_k,
  439.     CMD_list,
  440.     CMD_move,
  441.     CMD_next,
  442.     CMD_open,
  443.     CMD_print,
  444.     CMD_quit,
  445.     CMD_read,
  446.     CMD_substitute,
  447.     CMD_t,
  448.     CMD_undo,
  449.     CMD_vglobal,
  450.     CMD_write,
  451.     CMD_xit,
  452.     CMD_yank,
  453.     CMD_z,
  454.     CMD_bang
  455. };
  456.  
  457. static char_u dollar_command[2] = {'$', 0};
  458.  
  459. /*
  460.  * do_exmode(): Repeatedly get commands for the "Ex" mode, until the ":vi"
  461.  * command is given.
  462.  */
  463.     void
  464. do_exmode(improved)
  465.     int        improved;        /* TRUE for "improved Ex" mode */
  466. {
  467.     int        save_msg_scroll;
  468.     int        prev_msg_row;
  469.     linenr_T    prev_line;
  470.  
  471.     save_msg_scroll = msg_scroll;
  472.     ++RedrawingDisabled;        /* don't redisplay the window */
  473.     ++no_wait_return;            /* don't wait for return */
  474.     if (improved)
  475.     exmode_active = EXMODE_VIM;
  476.     else
  477.     {
  478.     settmode(TMODE_COOK);
  479.     exmode_active = EXMODE_NORMAL;
  480.     }
  481.  
  482.     State = NORMAL;
  483. #ifdef FEAT_GUI
  484.     /* Ignore scrollbar and mouse events in Ex mode */
  485.     ++hold_gui_events;
  486. #endif
  487. #ifdef FEAT_SNIFF
  488.     want_sniff_request = 0;    /* No K_SNIFF wanted */
  489. #endif
  490.  
  491.     MSG(_("Entering Ex mode.  Type \"visual\" to go to Normal mode."));
  492.     while (exmode_active)
  493.     {
  494.     msg_scroll = TRUE;
  495.     need_wait_return = FALSE;
  496.     ex_pressedreturn = FALSE;
  497.     ex_no_reprint = FALSE;
  498.     prev_msg_row = msg_row;
  499.     prev_line = curwin->w_cursor.lnum;
  500. #ifdef FEAT_SNIFF
  501.     ProcessSniffRequests();
  502. #endif
  503.     if (improved)
  504.     {
  505.         cmdline_row = msg_row;
  506.         do_cmdline(NULL, getexline, NULL, 0);
  507.     }
  508.     else
  509.         do_cmdline(NULL, getexmodeline, NULL, DOCMD_NOWAIT);
  510.     lines_left = Rows - 1;
  511.  
  512.     if (prev_line != curwin->w_cursor.lnum && !ex_no_reprint)
  513.     {
  514.         if (ex_pressedreturn)
  515.         {
  516.         /* go up one line, to overwrite the ":<CR>" line, so the
  517.          * output doensn't contain empty lines. */
  518.         msg_row = prev_msg_row;
  519.         if (prev_msg_row == Rows - 1)
  520.             msg_row--;
  521.         }
  522.         msg_col = 0;
  523.         print_line_no_prefix(curwin->w_cursor.lnum, FALSE);
  524.         msg_clr_eos();
  525.     }
  526.     else if (ex_pressedreturn)    /* must be at EOF */
  527.         EMSG(_("At end-of-file"));
  528.     }
  529.  
  530. #ifdef FEAT_GUI
  531.     --hold_gui_events;
  532. #endif
  533.     if (!improved)
  534.     settmode(TMODE_RAW);
  535.     --RedrawingDisabled;
  536.     --no_wait_return;
  537.     update_screen(CLEAR);
  538.     need_wait_return = FALSE;
  539.     msg_scroll = save_msg_scroll;
  540. }
  541.  
  542. /*
  543.  * Execute a simple command line.  Used for translated commands like "*".
  544.  */
  545.     int
  546. do_cmdline_cmd(cmd)
  547.     char_u    *cmd;
  548. {
  549.     return do_cmdline(cmd, NULL, NULL,
  550.                    DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
  551. }
  552.  
  553. /* Struct for storing a line inside a while loop */
  554. typedef struct
  555. {
  556.     char_u    *line;        /* command line */
  557.     linenr_T    lnum;        /* sourcing_lnum of the line */
  558. } wcmd_T;
  559.  
  560. /*
  561.  * do_cmdline(): execute one Ex command line
  562.  *
  563.  * 1. Execute "cmdline" when it is not NULL.
  564.  *    If "cmdline" is NULL, or more lines are needed, getline() is used.
  565.  * 2. Split up in parts separated with '|'.
  566.  *
  567.  * This function can be called recursively!
  568.  *
  569.  * flags:
  570.  * DOCMD_VERBOSE - The command will be included in the error message.
  571.  * DOCMD_NOWAIT  - Don't call wait_return() and friends.
  572.  * DOCMD_REPEAT  - Repeat execution until getline() returns NULL.
  573.  * DOCMD_KEYTYPED - Don't reset KeyTyped
  574.  *
  575.  * return FAIL if cmdline could not be executed, OK otherwise
  576.  */
  577.     int
  578. do_cmdline(cmdline, getline, cookie, flags)
  579.     char_u    *cmdline;
  580.     char_u    *(*getline) __ARGS((int, void *, int));
  581.     void    *cookie;        /* argument for getline() */
  582.     int        flags;
  583. {
  584.     char_u    *next_cmdline;        /* next cmd to execute */
  585.     char_u    *cmdline_copy = NULL;    /* copy of cmd line */
  586.     static int    recursive = 0;        /* recursive depth */
  587.     int        msg_didout_before_start = 0;
  588.     int        count = 0;        /* line number count */
  589.     int        did_inc = FALSE;    /* incremented RedrawingDisabled */
  590.     int        retval = OK;
  591. #ifdef FEAT_EVAL
  592.     struct condstack cstack;        /* conditional stack */
  593.     garray_T    lines_ga;        /* keep lines for ":while" */
  594.     int        current_line = 0;    /* active line in lines_ga */
  595. #endif
  596.     static int    call_depth = 0;        /* recursiveness */
  597.  
  598.     /* It's possible to create an endless loop with ":execute", catch that
  599.      * here.  The value of 200 allows nested function calls, ":source", etc. */
  600.     if (call_depth == 200)
  601.     {
  602.     EMSG(_("E169: Command too recursive"));
  603.     return FAIL;
  604.     }
  605.     ++call_depth;
  606.  
  607. #ifdef FEAT_EVAL
  608.     cstack.cs_idx = -1;
  609.     cstack.cs_whilelevel = 0;
  610.     cstack.cs_had_while = FALSE;
  611.     cstack.cs_had_endwhile = FALSE;
  612.     cstack.cs_had_continue = FALSE;
  613.     ga_init2(&lines_ga, (int)sizeof(wcmd_T), 10);
  614. #endif
  615.  
  616.     /*
  617.      * "did_emsg" will be set to TRUE when emsg() is used, in which case we
  618.      * cancel the whole command line, and any if/endif while/endwhile loop.
  619.      */
  620.     did_emsg = FALSE;
  621.  
  622.     /*
  623.      * KeyTyped is only set when calling vgetc().  Reset it here when not
  624.      * calling vgetc() (sourced command lines).
  625.      */
  626.     if (!(flags & DOCMD_KEYTYPED) && getline != getexline)
  627.     KeyTyped = FALSE;
  628.  
  629.     /*
  630.      * Continue executing command lines:
  631.      * - when inside an ":if" or ":while"
  632.      * - for multiple commands on one line, separated with '|'
  633.      * - when repeating until there are no more lines (for ":source")
  634.      */
  635.     next_cmdline = cmdline;
  636.     do
  637.     {
  638.     /* stop skipping cmds for an error msg after all endifs and endwhiles */
  639.     if (next_cmdline == NULL
  640. #ifdef FEAT_EVAL
  641.                 && cstack.cs_idx < 0
  642. #endif
  643.                             )
  644.         did_emsg = FALSE;
  645.  
  646.     /*
  647.      * 1. If repeating a line with ":while", get a line from lines_ga.
  648.      * 2. If no line given: Get an allocated line with getline().
  649.      * 3. If a line is given: Make a copy, so we can mess with it.
  650.      */
  651.  
  652. #ifdef FEAT_EVAL
  653.     /* 1. If repeating, get a previous line from lines_ga. */
  654.     if (cstack.cs_whilelevel && current_line < lines_ga.ga_len)
  655.     {
  656.         /* Each '|' separated command is stored separately in lines_ga, to
  657.          * be able to jump to it.  Don't use next_cmdline now. */
  658.         vim_free(cmdline_copy);
  659.         cmdline_copy = NULL;
  660.  
  661.         /* Check if a function has returned or aborted */
  662.         if (getline == get_func_line && func_has_ended(cookie))
  663.         {
  664.         retval = FAIL;
  665.         break;
  666.         }
  667.  
  668.         /* Check if a sourced file hit a ":finish" command. */
  669.         if (getline == getsourceline && source_finished(cookie))
  670.         {
  671.         retval = FAIL;
  672.         break;
  673.         }
  674.  
  675.         next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line;
  676.         sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum;
  677.     }
  678. #endif
  679.  
  680.     /* 2. If no line given, get an allocated line with getline(). */
  681.     if (next_cmdline == NULL)
  682.     {
  683.         /*
  684.          * Need to set msg_didout for the first line after an ":if",
  685.          * otherwise the ":if" will be overwritten.
  686.          */
  687.         if (count == 1 && getline == getexline)
  688.         msg_didout = TRUE;
  689.         if (getline == NULL || (next_cmdline = getline(':', cookie,
  690. #ifdef FEAT_EVAL
  691.             cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2
  692. #else
  693.             0
  694. #endif
  695.                 )) == NULL)
  696.         {
  697.         /* Don't call wait_return for aborted command line.  The NULL
  698.          * returned for the end of a sourced file or executed function
  699.          * doesn't do this. */
  700.         if (KeyTyped && !(flags & DOCMD_REPEAT))
  701.             need_wait_return = FALSE;
  702.         retval = FAIL;
  703.         break;
  704.         }
  705.     }
  706.  
  707.     /* 3. Make a copy of the command so we can mess with it. */
  708.     else if (cmdline_copy == NULL)
  709.     {
  710.         next_cmdline = vim_strsave(next_cmdline);
  711.         if (next_cmdline == NULL)
  712.         {
  713.         retval = FAIL;
  714.         break;
  715.         }
  716.     }
  717.     cmdline_copy = next_cmdline;
  718.  
  719. #ifdef FEAT_EVAL
  720.     /*
  721.      * Save the current line when inside a ":while", and when the command
  722.      * looks like a ":while", because we may need it later.
  723.      * When there is a '|' and another command, it is stored separately,
  724.      * because we need to be able to jump back to it from an :endwhile.
  725.      */
  726.     if (       current_line == lines_ga.ga_len
  727.         && (cstack.cs_whilelevel || has_while_cmd(next_cmdline))
  728.         && ga_grow(&lines_ga, 1) == OK)
  729.     {
  730.         ((wcmd_T *)(lines_ga.ga_data))[current_line].line =
  731.                             vim_strsave(next_cmdline);
  732.         ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum = sourcing_lnum;
  733.         ++lines_ga.ga_len;
  734.         --lines_ga.ga_room;
  735.     }
  736.     did_endif = FALSE;
  737. #endif
  738.  
  739.     if (count++ == 0)
  740.     {
  741.         /*
  742.          * All output from the commands is put below each other, without
  743.          * waiting for a return. Don't do this when executing commands
  744.          * from a script or when being called recursive (e.g. for ":e
  745.          * +command file").
  746.          */
  747.         if (!(flags & DOCMD_NOWAIT) && !recursive)
  748.         {
  749.         msg_didout_before_start = msg_didout;
  750.         msg_didany = FALSE; /* no output yet */
  751.         msg_start();
  752.         msg_scroll = TRUE;  /* put messages below each other */
  753.         ++no_wait_return;   /* dont wait for return until finished */
  754.         ++RedrawingDisabled;
  755.         did_inc = TRUE;
  756.         }
  757.     }
  758.  
  759.     if (p_verbose >= 15 && sourcing_name != NULL)
  760.     {
  761.         int    c = -1;
  762.  
  763.         ++no_wait_return;
  764.         msg_scroll = TRUE;        /* always scroll up, don't overwrite */
  765.         /* Truncate long lines, smsg() can't handle that. */
  766.         if (STRLEN(cmdline_copy) > 200)
  767.         {
  768.         c = cmdline_copy[200];
  769.         cmdline_copy[200] = NUL;
  770.         }
  771.         smsg((char_u *)_("line %ld: %s"),
  772.                        (long)sourcing_lnum, cmdline_copy);
  773.         msg_puts((char_u *)"\n");   /* don't overwrite this either */
  774.         if (c >= 0)
  775.         cmdline_copy[200] = c;
  776.         cmdline_row = msg_row;
  777.         --no_wait_return;
  778.     }
  779.  
  780.     /*
  781.      * 2. Execute one '|' separated command.
  782.      *    do_one_cmd() will return NULL if there is no trailing '|'.
  783.      *    "cmdline_copy" can change, e.g. for '%' and '#' expansion.
  784.      */
  785.     ++recursive;
  786.     next_cmdline = do_one_cmd(&cmdline_copy, flags & DOCMD_VERBOSE,
  787. #ifdef FEAT_EVAL
  788.                 &cstack,
  789. #endif
  790.                 getline, cookie);
  791.     --recursive;
  792.     if (next_cmdline == NULL)
  793.     {
  794.         vim_free(cmdline_copy);
  795.         cmdline_copy = NULL;
  796. #ifdef FEAT_CMDHIST
  797.         /*
  798.          * If the command was typed, remember it for the ':' register.
  799.          * Do this AFTER executing the command to make :@: work.
  800.          */
  801.         if (getline == getexline && new_last_cmdline != NULL)
  802.         {
  803.         vim_free(last_cmdline);
  804.         last_cmdline = new_last_cmdline;
  805.         new_last_cmdline = NULL;
  806.         }
  807. #endif
  808.     }
  809.     else
  810.     {
  811.         /* need to copy the command after the '|' to cmdline_copy, for the
  812.          * next do_one_cmd() */
  813.         mch_memmove(cmdline_copy, next_cmdline, STRLEN(next_cmdline) + 1);
  814.         next_cmdline = cmdline_copy;
  815.     }
  816.  
  817.  
  818. #ifdef FEAT_EVAL
  819.     /* reset did_emsg for a function that is not aborted by an error */
  820.     if (did_emsg && getline == get_func_line && !func_has_abort(cookie))
  821.         did_emsg = FALSE;
  822.  
  823.     if (cstack.cs_whilelevel)
  824.     {
  825.         ++current_line;
  826.  
  827.         /*
  828.          * An ":endwhile" and ":continue" is handled here.
  829.          * If we were executing commands, jump back to the ":while".
  830.          * If we were not executing commands, decrement whilelevel.
  831.          */
  832.         if (cstack.cs_had_endwhile || cstack.cs_had_continue)
  833.         {
  834.         if (cstack.cs_had_endwhile)
  835.             cstack.cs_had_endwhile = FALSE;
  836.         else
  837.             cstack.cs_had_continue = FALSE;
  838.  
  839.         /* Jump back to the matching ":while".  Be careful not to use
  840.          * a cs_line[] from an entry that isn't a ":while": It would
  841.          * make "current_line" invalid and can cause a crash. */
  842.         if (!did_emsg
  843.             && cstack.cs_idx >= 0
  844.             && (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE)
  845.             && cstack.cs_line[cstack.cs_idx] >= 0
  846.             && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE))
  847.         {
  848.             current_line = cstack.cs_line[cstack.cs_idx];
  849.             cstack.cs_had_while = TRUE;    /* note we jumped there */
  850.             line_breakcheck();        /* check if CTRL-C typed */
  851.         }
  852.         else /* can only get here with ":endwhile" */
  853.         {
  854.             --cstack.cs_whilelevel;
  855.             if (cstack.cs_idx >= 0)
  856.             --cstack.cs_idx;
  857.         }
  858.         }
  859.  
  860.         /*
  861.          * For a ":while" we need to remember the line number.
  862.          */
  863.         else if (cstack.cs_had_while)
  864.         {
  865.         cstack.cs_had_while = FALSE;
  866.         cstack.cs_line[cstack.cs_idx] = current_line - 1;
  867.         }
  868.     }
  869.  
  870.     /*
  871.      * When not inside any ":while" loop, clear remembered lines.
  872.      */
  873.     if (!cstack.cs_whilelevel)
  874.     {
  875.         if (lines_ga.ga_len > 0)
  876.         {
  877.         sourcing_lnum =
  878.                ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum;
  879.         free_cmdlines(&lines_ga);
  880.         }
  881.         current_line = 0;
  882.     }
  883. #endif /* FEAT_EVAL */
  884.  
  885.     }
  886.     /*
  887.      * Continue executing command lines when:
  888.      * - no CTRL-C typed
  889.      * - didn't get an error message or lines are not typed
  890.      * - there is a command after '|', inside a :if or :while, or looping for
  891.      *     ":source" command.
  892.      */
  893.     while (!got_int
  894.         && !(did_emsg && (getline == getexmodeline || getline == getexline))
  895.         && (next_cmdline != NULL
  896. #ifdef FEAT_EVAL
  897.             || cstack.cs_idx >= 0
  898. #endif
  899.             || (flags & DOCMD_REPEAT)));
  900.  
  901.     vim_free(cmdline_copy);
  902. #ifdef FEAT_EVAL
  903.     free_cmdlines(&lines_ga);
  904.     ga_clear(&lines_ga);
  905.  
  906.     if (cstack.cs_idx >= 0
  907.         && ((getline == getsourceline && !source_finished(cookie))
  908.         || (getline == get_func_line && !func_has_ended(cookie))))
  909.     {
  910.     if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE)
  911.         EMSG(_("E170: Missing :endwhile"));
  912.     else
  913.         EMSG(_("E171: Missing :endif"));
  914.     }
  915.  
  916.     /*
  917.      * Go to debug mode when returning from a function in which we are
  918.      * single-stepping.
  919.      */
  920.     if ((getline == getsourceline || getline == get_func_line)
  921.         && debug_level + 1 <= debug_break_level)
  922.     do_debug(getline == getsourceline
  923.         ? (char_u *)_("End of sourced file")
  924.         : (char_u *)_("End of function"));
  925. #endif
  926.  
  927.     /*
  928.      * If there was too much output to fit on the command line, ask the user to
  929.      * hit return before redrawing the screen. With the ":global" command we do
  930.      * this only once after the command is finished.
  931.      */
  932.     if (did_inc)
  933.     {
  934.     --RedrawingDisabled;
  935.     --no_wait_return;
  936.     msg_scroll = FALSE;
  937.  
  938.     /*
  939.      * When just finished an ":if"-":else" which was typed, no need to
  940.      * wait for hit-return.  Also for an error situation.
  941.      */
  942.     if (retval == FAIL
  943. #ifdef FEAT_EVAL
  944.         || (did_endif && KeyTyped && !did_emsg)
  945. #endif
  946.                         )
  947.     {
  948.         need_wait_return = FALSE;
  949.         msg_didany = FALSE;        /* don't wait when restarting edit */
  950.     }
  951.     else if (need_wait_return)
  952.     {
  953.         /*
  954.          * The msg_start() above clears msg_didout. The wait_return we do
  955.          * here should not overwrite the command that may be shown before
  956.          * doing that.
  957.          */
  958.         msg_didout |= msg_didout_before_start;
  959.         wait_return(FALSE);
  960.     }
  961.     }
  962.  
  963. #ifndef FEAT_EVAL
  964.     /*
  965.      * Reset if_level, in case a sourced script file contains more ":if" than
  966.      * ":endif" (could be ":if x | foo | endif").
  967.      */
  968.     if_level = 0;
  969. #endif
  970.  
  971.     --call_depth;
  972.     return retval;
  973. }
  974.  
  975. #ifdef FEAT_EVAL
  976.     static void
  977. free_cmdlines(gap)
  978.     garray_T    *gap;
  979. {
  980.     while (gap->ga_len > 0)
  981.     {
  982.     vim_free(((wcmd_T *)(gap->ga_data))[gap->ga_len - 1].line);
  983.     --gap->ga_len;
  984.     ++gap->ga_room;
  985.     }
  986. }
  987. #endif
  988.  
  989. /*
  990.  * Execute one Ex command.
  991.  *
  992.  * If 'sourcing' is TRUE, the command will be included in the error message.
  993.  *
  994.  * 1. skip comment lines and leading space
  995.  * 2. handle command modifiers
  996.  * 3. parse range
  997.  * 4. parse command
  998.  * 5. parse arguments
  999.  * 6. switch on command name
  1000.  *
  1001.  * Note: "getline" can be NULL.
  1002.  *
  1003.  * This function may be called recursively!
  1004.  */
  1005. #if (_MSC_VER == 1200)
  1006. /*
  1007.  * Optimisation bug in VC++ version 6.0
  1008.  * TODO: check this is still present after each service pack
  1009.  */
  1010. #pragma optimize( "g", off )
  1011. #endif
  1012.     static char_u *
  1013. do_one_cmd(cmdlinep, sourcing,
  1014. #ifdef FEAT_EVAL
  1015.                 cstack,
  1016. #endif
  1017.                     getline, cookie)
  1018.     char_u        **cmdlinep;
  1019.     int            sourcing;
  1020. #ifdef FEAT_EVAL
  1021.     struct condstack    *cstack;
  1022. #endif
  1023.     char_u        *(*getline) __ARGS((int, void *, int));
  1024.     void        *cookie;        /* argument for getline() */
  1025. {
  1026.     char_u        *p;
  1027.     linenr_T        lnum;
  1028.     long        n;
  1029.     char_u        *errormsg = NULL;    /* error message */
  1030.     exarg_T        ea;            /* Ex command arguments */
  1031.     long        verbose_save = -1;
  1032.     int            save_msg_scroll = 0;
  1033.     int            did_silent = 0;
  1034.     int            did_esilent = 0;
  1035.     cmdmod_T        save_cmdmod;
  1036.  
  1037.     vim_memset(&ea, 0, sizeof(ea));
  1038.     ea.line1 = 1;
  1039.     ea.line2 = 1;
  1040. #ifdef FEAT_EVAL
  1041.     ++debug_level;
  1042. #endif
  1043.  
  1044.     /* when not editing the last file :q has to be typed twice */
  1045.     if (quitmore
  1046. #ifdef FEAT_EVAL
  1047.         /* avoid that a function call in 'statusline' does this */
  1048.         && getline != get_func_line
  1049. #endif
  1050.         )
  1051.     --quitmore;
  1052.  
  1053.     /*
  1054.      * Reset browse, confirm, etc..  They are restored when returning, for
  1055.      * recursive calls.
  1056.      */
  1057.     save_cmdmod = cmdmod;
  1058.     vim_memset(&cmdmod, 0, sizeof(cmdmod));
  1059.  
  1060.     /*
  1061.      * Repeat until no more command modifiers are found.
  1062.      */
  1063.     ea.cmd = *cmdlinep;
  1064.     for (;;)
  1065.     {
  1066. /*
  1067.  * 1. skip comment lines and leading white space and colons
  1068.  */
  1069.     while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':')
  1070.         ++ea.cmd;
  1071.  
  1072.     /* in ex mode, an empty line works like :+ */
  1073.     if (*ea.cmd == NUL && exmode_active
  1074.             && (getline == getexmodeline || getline == getexline))
  1075.     {
  1076.         ea.cmd = (char_u *)"+";
  1077.         ex_pressedreturn = TRUE;
  1078.     }
  1079.  
  1080.     /* ignore comment and empty lines */
  1081.     if (*ea.cmd == '"' || *ea.cmd == NUL)
  1082.         goto doend;
  1083.  
  1084. /*
  1085.  * 2. handle command modifiers.
  1086.  */
  1087.     p = ea.cmd;
  1088.     if (isdigit(*ea.cmd))
  1089.         p = skipwhite(skipdigits(ea.cmd));
  1090.     switch (*p)
  1091.     {
  1092.         case 'a':    if (!checkforcmd(&ea.cmd, "aboveleft", 3))
  1093.                 break;
  1094. #ifdef FEAT_WINDOWS
  1095.             cmdmod.split |= WSP_ABOVE;
  1096. #endif
  1097.             continue;
  1098.  
  1099.         case 'b':    if (checkforcmd(&ea.cmd, "belowright", 3))
  1100.             {
  1101. #ifdef FEAT_WINDOWS
  1102.                 cmdmod.split |= WSP_BELOW;
  1103. #endif
  1104.                 continue;
  1105.             }
  1106.             if (checkforcmd(&ea.cmd, "browse", 3))
  1107.             {
  1108. #ifdef FEAT_BROWSE
  1109.                 cmdmod.browse = TRUE;
  1110. #endif
  1111.                 continue;
  1112.             }
  1113.             if (!checkforcmd(&ea.cmd, "botright", 2))
  1114.                 break;
  1115. #ifdef FEAT_WINDOWS
  1116.             cmdmod.split |= WSP_BOT;
  1117. #endif
  1118.             continue;
  1119.  
  1120.         case 'c':    if (!checkforcmd(&ea.cmd, "confirm", 4))
  1121.                 break;
  1122. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  1123.             cmdmod.confirm = TRUE;
  1124. #endif
  1125.             continue;
  1126.  
  1127.             /* ":hide" and ":hide | cmd" are not modifiers */
  1128.         case 'h':    if (p != ea.cmd || !checkforcmd(&p, "hide", 3)
  1129.                            || *p == NUL || ends_excmd(*p))
  1130.                 break;
  1131.             ea.cmd = p;
  1132.             cmdmod.hide = TRUE;
  1133.             continue;
  1134.  
  1135.         case 'l':    if (!checkforcmd(&ea.cmd, "leftabove", 5))
  1136.                 break;
  1137. #ifdef FEAT_WINDOWS
  1138.             cmdmod.split |= WSP_ABOVE;
  1139. #endif
  1140.             continue;
  1141.  
  1142.         case 'r':    if (!checkforcmd(&ea.cmd, "rightbelow", 6))
  1143.                 break;
  1144. #ifdef FEAT_WINDOWS
  1145.             cmdmod.split |= WSP_BELOW;
  1146. #endif
  1147.             continue;
  1148.  
  1149.         case 's':    if (!checkforcmd(&ea.cmd, "silent", 3))
  1150.                 break;
  1151.             ++did_silent;
  1152.             ++msg_silent;
  1153.             save_msg_scroll = msg_scroll;
  1154.             if (*ea.cmd == '!' && !vim_iswhite(ea.cmd[-1]))
  1155.             {
  1156.                 /* ":silent!", but not "silent !cmd" */
  1157.                 ea.cmd = skipwhite(ea.cmd + 1);
  1158.                 ++emsg_silent;
  1159.                 ++did_esilent;
  1160.             }
  1161.             continue;
  1162.  
  1163.         case 't':    if (!checkforcmd(&ea.cmd, "topleft", 2))
  1164.                 break;
  1165. #ifdef FEAT_WINDOWS
  1166.             cmdmod.split |= WSP_TOP;
  1167. #endif
  1168.             continue;
  1169.  
  1170.         case 'v':    if (checkforcmd(&ea.cmd, "vertical", 4))
  1171.             {
  1172. #ifdef FEAT_VERTSPLIT
  1173.                 cmdmod.split |= WSP_VERT;
  1174. #endif
  1175.                 continue;
  1176.             }
  1177.             if (!checkforcmd(&p, "verbose", 4))
  1178.                 break;
  1179.             if (verbose_save < 0)
  1180.                 verbose_save = p_verbose;
  1181.             p_verbose = atoi((char *)ea.cmd);
  1182.             if (p_verbose == 0)
  1183.                 p_verbose = 1;
  1184.             ea.cmd = p;
  1185.             continue;
  1186.     }
  1187.     break;
  1188.     }
  1189.  
  1190. #ifdef FEAT_EVAL
  1191.     ea.skip = did_emsg || (cstack->cs_idx >= 0
  1192.              && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE));
  1193. #else
  1194.     ea.skip = (if_level > 0);
  1195. #endif
  1196.  
  1197. #ifdef FEAT_EVAL
  1198.     /* May go to debug mode */
  1199.     dbg_check_breakpoint(&ea);
  1200. #endif
  1201.  
  1202. /*
  1203.  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  1204.  *
  1205.  * where 'addr' is:
  1206.  *
  1207.  * %          (entire file)
  1208.  * $  [+-NUM]
  1209.  * 'x [+-NUM] (where x denotes a currently defined mark)
  1210.  * .  [+-NUM]
  1211.  * [+-NUM]..
  1212.  * NUM
  1213.  *
  1214.  * The ea.cmd pointer is updated to point to the first character following the
  1215.  * range spec. If an initial address is found, but no second, the upper bound
  1216.  * is equal to the lower.
  1217.  */
  1218.  
  1219.     /* repeat for all ',' or ';' separated addresses */
  1220.     for (;;)
  1221.     {
  1222.     ea.line1 = ea.line2;
  1223.     ea.line2 = curwin->w_cursor.lnum;   /* default is current line number */
  1224.     ea.cmd = skipwhite(ea.cmd);
  1225.     lnum = get_address(&ea.cmd, ea.skip);
  1226.     if (ea.cmd == NULL)            /* error detected */
  1227.         goto doend;
  1228.     if (lnum == MAXLNUM)
  1229.     {
  1230.         if (*ea.cmd == '%')            /* '%' - all lines */
  1231.         {
  1232.         ++ea.cmd;
  1233.         ea.line1 = 1;
  1234.         ea.line2 = curbuf->b_ml.ml_line_count;
  1235.         ++ea.addr_count;
  1236.         }
  1237.                         /* '*' - visual area */
  1238.         else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL)
  1239.         {
  1240.         pos_T        *fp;
  1241.  
  1242.         ++ea.cmd;
  1243.         if (!ea.skip)
  1244.         {
  1245.             fp = getmark('<', FALSE);
  1246.             if (check_mark(fp) == FAIL)
  1247.             goto doend;
  1248.             ea.line1 = fp->lnum;
  1249.             fp = getmark('>', FALSE);
  1250.             if (check_mark(fp) == FAIL)
  1251.             goto doend;
  1252.             ea.line2 = fp->lnum;
  1253.             ++ea.addr_count;
  1254.         }
  1255.         }
  1256.     }
  1257.     else
  1258.         ea.line2 = lnum;
  1259.     ea.addr_count++;
  1260.  
  1261.     if (*ea.cmd == ';')
  1262.     {
  1263.         if (!ea.skip)
  1264.         curwin->w_cursor.lnum = ea.line2;
  1265.     }
  1266.     else if (*ea.cmd != ',')
  1267.         break;
  1268.     ++ea.cmd;
  1269.     }
  1270.  
  1271.     /* One address given: set start and end lines */
  1272.     if (ea.addr_count == 1)
  1273.     {
  1274.     ea.line1 = ea.line2;
  1275.         /* ... but only implicit: really no address given */
  1276.     if (lnum == MAXLNUM)
  1277.         ea.addr_count = 0;
  1278.     }
  1279.  
  1280.     /* Don't leave the cursor on an illegal line (caused by ';') */
  1281.     check_cursor_lnum();
  1282.  
  1283. /*
  1284.  * 4. parse command
  1285.  */
  1286.  
  1287.     /*
  1288.      * Skip ':' and any white space
  1289.      */
  1290.     ea.cmd = skipwhite(ea.cmd);
  1291.     while (*ea.cmd == ':')
  1292.     ea.cmd = skipwhite(ea.cmd + 1);
  1293.  
  1294.     /*
  1295.      * If we got a line, but no command, then go to the line.
  1296.      * If we find a '|' or '\n' we set ea.nextcmd.
  1297.      */
  1298.     if (*ea.cmd == NUL || *ea.cmd == '"' ||
  1299.                    (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
  1300.     {
  1301.     /*
  1302.      * strange vi behaviour:
  1303.      * ":3"        jumps to line 3
  1304.      * ":3|..."    prints line 3
  1305.      * ":|"        prints current line
  1306.      */
  1307.     if (ea.skip)        /* skip this if inside :if */
  1308.         goto doend;
  1309.     if (*ea.cmd == '|')
  1310.     {
  1311.         ea.cmdidx = CMD_print;
  1312.         ea.argt = RANGE+COUNT+TRLBAR;
  1313.         if ((errormsg = invalid_range(&ea)) == NULL)
  1314.         {
  1315.         correct_range(&ea);
  1316.         ex_print(&ea);
  1317.         }
  1318.     }
  1319.     else if (ea.addr_count != 0)
  1320.     {
  1321.         if (ea.line2 < 0)
  1322.         errormsg = invalid_range(&ea);
  1323.         else
  1324.         {
  1325.         if (ea.line2 == 0)
  1326.             curwin->w_cursor.lnum = 1;
  1327.         else if (ea.line2 > curbuf->b_ml.ml_line_count)
  1328.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1329.         else
  1330.             curwin->w_cursor.lnum = ea.line2;
  1331.         beginline(BL_SOL | BL_FIX);
  1332.         }
  1333.     }
  1334.     goto doend;
  1335.     }
  1336.  
  1337.     /* Find the command and let "p" point to after it. */
  1338.     p = find_command(&ea, NULL);
  1339.  
  1340. #ifdef FEAT_USR_CMDS
  1341.     if (p == NULL)
  1342.     {
  1343.     if (!ea.skip)
  1344.         errormsg = (char_u *)_("Ambiguous use of user-defined command");
  1345.     goto doend;
  1346.     }
  1347.     /* Check for wrong commands. */
  1348.     if (*p == '!' && ea.cmd[1] == 0151 && ea.cmd[0] == 78)
  1349.     {
  1350.     errormsg = uc_fun_cmd();
  1351.     goto doend;
  1352.     }
  1353. #endif
  1354.     if (ea.cmdidx == CMD_SIZE)
  1355.     {
  1356.     if (!ea.skip)
  1357.     {
  1358.         STRCPY(IObuff, _("Not an editor command"));
  1359.         if (!sourcing)
  1360.         {
  1361.         STRCAT(IObuff, ": ");
  1362.         STRNCAT(IObuff, *cmdlinep, 40);
  1363.         }
  1364.         errormsg = IObuff;
  1365.     }
  1366.     goto doend;
  1367.     }
  1368.  
  1369. #ifndef FEAT_EVAL
  1370.     /*
  1371.      * When the expression evaluation is disabled, recognize the ":if" and
  1372.      * ":endif" commands and ignore everything in between it.
  1373.      */
  1374.     if (ea.cmdidx == CMD_if)
  1375.     ++if_level;
  1376.     if (if_level)
  1377.     {
  1378.     if (ea.cmdidx == CMD_endif)
  1379.         --if_level;
  1380.     goto doend;
  1381.     }
  1382.  
  1383. #endif
  1384.  
  1385.     if (*p == '!' && ea.cmdidx != CMD_substitute)    /* forced commands */
  1386.     {
  1387.     ++p;
  1388.     ea.forceit = TRUE;
  1389.     }
  1390.     else
  1391.     ea.forceit = FALSE;
  1392.  
  1393. /*
  1394.  * 5. parse arguments
  1395.  */
  1396. #ifdef FEAT_USR_CMDS
  1397.     if (!USER_CMDIDX(ea.cmdidx))
  1398. #endif
  1399.     ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt;
  1400.  
  1401.     if (!ea.skip)
  1402.     {
  1403. #ifdef HAVE_SANDBOX
  1404.     if (sandbox != 0 && !(ea.argt & SBOXOK))
  1405.     {
  1406.         /* Command not allowed in sandbox. */
  1407.         errormsg = (char_u *)_(e_sandbox);
  1408.         goto doend;
  1409.     }
  1410. #endif
  1411.     if (!curbuf->b_p_ma && (ea.argt & MODIFY))
  1412.     {
  1413.         /* Command not allowed in non-'modifiable' buffer */
  1414.         errormsg = (char_u *)_(e_modifiable);
  1415.         goto doend;
  1416.     }
  1417. #ifdef FEAT_CMDWIN
  1418.     if (cmdwin_type != 0 && !(ea.argt & CMDWIN)
  1419. # ifdef FEAT_USR_CMDS
  1420.         && !USER_CMDIDX(ea.cmdidx)
  1421. # endif
  1422.        )
  1423.     {
  1424.         /* Command not allowed in cmdline window. */
  1425.         errormsg = (char_u *)_(e_cmdwin);
  1426.         goto doend;
  1427.     }
  1428. #endif
  1429.  
  1430.     if (!(ea.argt & RANGE) && ea.addr_count > 0)    /* no range allowed */
  1431.     {
  1432.         errormsg = (char_u *)_(e_norange);
  1433.         goto doend;
  1434.     }
  1435.     }
  1436.  
  1437.     if (!(ea.argt & BANG) && ea.forceit)    /* no <!> allowed */
  1438.     {
  1439.     errormsg = (char_u *)_(e_nobang);
  1440.     if (ea.cmdidx == CMD_help)
  1441.         errormsg = (char_u *)_("Don't panic!");
  1442.     goto doend;
  1443.     }
  1444.  
  1445.     /*
  1446.      * Don't complain about the range if it is not used
  1447.      * (could happen if line_count is accidentally set to 0).
  1448.      */
  1449.     if (!ea.skip)
  1450.     {
  1451.     /*
  1452.      * If the range is backwards, ask for confirmation and, if given, swap
  1453.      * ea.line1 & ea.line2 so it's forwards again.
  1454.      * When global command is busy, don't ask, will fail below.
  1455.      */
  1456.     if (!global_busy && ea.line1 > ea.line2)
  1457.     {
  1458.         if (sourcing)
  1459.         {
  1460.         errormsg = (char_u *)_("Backwards range given");
  1461.         goto doend;
  1462.         }
  1463.         else
  1464.         {
  1465.         int    msg_silent_save = msg_silent;
  1466.  
  1467.         msg_silent = 0;
  1468.         if (ask_yesno((char_u *)
  1469.             _("Backwards range given, OK to swap"), FALSE) != 'y')
  1470.         goto doend;
  1471.         msg_silent = msg_silent_save;
  1472.         }
  1473.         lnum = ea.line1;
  1474.         ea.line1 = ea.line2;
  1475.         ea.line2 = lnum;
  1476.     }
  1477.     if ((errormsg = invalid_range(&ea)) != NULL)
  1478.         goto doend;
  1479.     }
  1480.  
  1481.     if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */
  1482.     ea.line2 = 1;
  1483.  
  1484.     correct_range(&ea);
  1485.  
  1486. #ifdef FEAT_FOLDING
  1487.     if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy)
  1488.     {
  1489.     /* Put the first line at the start of a closed fold, put the last line
  1490.      * at the end of a closed fold. */
  1491.     (void)hasFolding(ea.line1, &ea.line1, NULL);
  1492.     (void)hasFolding(ea.line2, NULL, &ea.line2);
  1493.     }
  1494. #endif
  1495.  
  1496. #ifdef FEAT_QUICKFIX
  1497.     /*
  1498.      * For the :make and :grep commands we insert the 'makeprg'/'grepprg'
  1499.      * option here, so things like % get expanded.
  1500.      */
  1501.     if (ea.cmdidx == CMD_make || ea.cmdidx == CMD_grep
  1502.                           || ea.cmdidx == CMD_grepadd)
  1503.     {
  1504.     char_u        *new_cmdline;
  1505.     char_u        *program;
  1506.     char_u        *pos;
  1507.     char_u        *ptr;
  1508.     int        len;
  1509.     int        i;
  1510.  
  1511.     if (ea.cmdidx == CMD_grep || ea.cmdidx == CMD_grepadd)
  1512.     {
  1513.         if (*curbuf->b_p_gp == NUL)
  1514.         program = p_gp;
  1515.         else
  1516.         program = curbuf->b_p_gp;
  1517.     }
  1518.     else
  1519.     {
  1520.         if (*curbuf->b_p_mp == NUL)
  1521.         program = p_mp;
  1522.         else
  1523.         program = curbuf->b_p_mp;
  1524.     }
  1525.  
  1526.     p = skipwhite(p);
  1527.  
  1528.     if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL)
  1529.     {                /* replace $* by given arguments */
  1530.         i = 1;
  1531.         while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL)
  1532.         ++i;
  1533.         len = (int)STRLEN(p);
  1534.         new_cmdline = alloc((int)(STRLEN(program) + i * (len - 2) + 1));
  1535.         if (new_cmdline == NULL)
  1536.         goto doend;            /* out of memory */
  1537.         ptr = new_cmdline;
  1538.         while ((pos = (char_u *)strstr((char *)program, "$*")) != NULL)
  1539.         {
  1540.         i = (int)(pos - program);
  1541.         STRNCPY(ptr, program, i);
  1542.         STRCPY(ptr += i, p);
  1543.         ptr += len;
  1544.         program = pos + 2;
  1545.         }
  1546.         STRCPY(ptr, program);
  1547.     }
  1548.     else
  1549.     {
  1550.         new_cmdline = alloc((int)(STRLEN(program) + STRLEN(p) + 2));
  1551.         if (new_cmdline == NULL)
  1552.         goto doend;            /* out of memory */
  1553.         STRCPY(new_cmdline, program);
  1554.         STRCAT(new_cmdline, " ");
  1555.         STRCAT(new_cmdline, p);
  1556.     }
  1557.     msg_make(p);
  1558.     /* 'ea.cmd' is not set here, because it is not used at CMD_make */
  1559.     vim_free(*cmdlinep);
  1560.     *cmdlinep = new_cmdline;
  1561.     p = new_cmdline;
  1562.     }
  1563. #endif
  1564.  
  1565.     /*
  1566.      * Skip to start of argument.
  1567.      * Don't do this for the ":!" command, because ":!! -l" needs the space.
  1568.      */
  1569.     if (ea.cmdidx == CMD_bang)
  1570.     ea.arg = p;
  1571.     else
  1572.     ea.arg = skipwhite(p);
  1573.  
  1574.     if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update)
  1575.     {
  1576.     if (*ea.arg == '>')            /* append */
  1577.     {
  1578.         if (*++ea.arg != '>')        /* typed wrong */
  1579.         {
  1580.         errormsg = (char_u *)_("Use w or w>>");
  1581.         goto doend;
  1582.         }
  1583.         ea.arg = skipwhite(ea.arg + 1);
  1584.         ea.append = TRUE;
  1585.     }
  1586.     else if (*ea.arg == '!' && ea.cmdidx == CMD_write)  /* :w !filter */
  1587.     {
  1588.         ++ea.arg;
  1589.         ea.usefilter = TRUE;
  1590.     }
  1591.     }
  1592.  
  1593.     if (ea.cmdidx == CMD_read)
  1594.     {
  1595.     if (ea.forceit)
  1596.     {
  1597.         ea.usefilter = TRUE;        /* :r! filter if ea.forceit */
  1598.         ea.forceit = FALSE;
  1599.     }
  1600.     else if (*ea.arg == '!')        /* :r !filter */
  1601.     {
  1602.         ++ea.arg;
  1603.         ea.usefilter = TRUE;
  1604.     }
  1605.     }
  1606.  
  1607.     if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift)
  1608.     {
  1609.     ea.amount = 1;
  1610.     while (*ea.arg == *ea.cmd)        /* count number of '>' or '<' */
  1611.     {
  1612.         ++ea.arg;
  1613.         ++ea.amount;
  1614.     }
  1615.     ea.arg = skipwhite(ea.arg);
  1616.     }
  1617.  
  1618.     /*
  1619.      * Check for "++opt=val" argument.
  1620.      */
  1621.     if (ea.argt & ARGOPT)
  1622.     while (ea.arg[0] == '+' && ea.arg[1] == '+')
  1623.         if (getargopt(&ea) == FAIL)
  1624.         {
  1625.         errormsg = (char_u *)_(e_invarg);
  1626.         goto doend;
  1627.         }
  1628.  
  1629.     /*
  1630.      * Check for "+command" argument, before checking for next command.
  1631.      * Don't do this for ":read !cmd" and ":write !cmd".
  1632.      */
  1633.     if ((ea.argt & EDITCMD) && !ea.usefilter)
  1634.     ea.do_ecmd_cmd = getargcmd(&ea.arg);
  1635.  
  1636.     /*
  1637.      * Check for '|' to separate commands and '"' to start comments.
  1638.      * Don't do this for ":read !cmd" and ":write !cmd".
  1639.      */
  1640.     if ((ea.argt & TRLBAR) && !ea.usefilter)
  1641.     separate_nextcmd(&ea);
  1642.  
  1643.     /*
  1644.      * Check for <newline> to end a shell command.
  1645.      * Also do this for ":read !cmd" and ":write !cmd".
  1646.      */
  1647.     else if (ea.cmdidx == CMD_bang || ea.usefilter)
  1648.     {
  1649.     for (p = ea.arg; *p; ++p)
  1650.     {
  1651.         if (*p == '\\' && p[1])
  1652.         ++p;
  1653.         else if (*p == '\n')
  1654.         {
  1655.         ea.nextcmd = p + 1;
  1656.         *p = NUL;
  1657.         break;
  1658.         }
  1659.     }
  1660.     }
  1661.  
  1662.     if ((ea.argt & DFLALL) && ea.addr_count == 0)
  1663.     {
  1664.     ea.line1 = 1;
  1665.     ea.line2 = curbuf->b_ml.ml_line_count;
  1666.     }
  1667.  
  1668.     /* accept numbered register only when no count allowed (:put) */
  1669.     if (       (ea.argt & REGSTR)
  1670.         && *ea.arg != NUL
  1671. #ifdef FEAT_USR_CMDS
  1672.         && valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
  1673.                            && USER_CMDIDX(ea.cmdidx)))
  1674.         /* Do not allow register = for user commands */
  1675.         && (!USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
  1676. #else
  1677.         && valid_yank_reg(*ea.arg, ea.cmdidx != CMD_put)
  1678. #endif
  1679.         && !((ea.argt & COUNT) && isdigit(*ea.arg)))
  1680.     {
  1681.     ea.regname = *ea.arg++;
  1682. #ifdef FEAT_EVAL
  1683.     /* for '=' register: accept the rest of the line as an expression */
  1684.     if (ea.arg[-1] == '=' && ea.arg[0] != NUL)
  1685.     {
  1686.         set_expr_line(vim_strsave(ea.arg));
  1687.         ea.arg += STRLEN(ea.arg);
  1688.     }
  1689. #endif
  1690.     ea.arg = skipwhite(ea.arg);
  1691.     }
  1692.  
  1693.     /*
  1694.      * Check for a count.  When accepting a BUFNAME, don't use "123foo" as a
  1695.      * count, it's a buffer name.
  1696.      */
  1697.     if ((ea.argt & COUNT) && isdigit(*ea.arg)
  1698.         && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL
  1699.                               || vim_iswhite(*p)))
  1700.     {
  1701.     n = getdigits(&ea.arg);
  1702.     ea.arg = skipwhite(ea.arg);
  1703.     if (n <= 0)
  1704.     {
  1705.         errormsg = (char_u *)_(e_zerocount);
  1706.         goto doend;
  1707.     }
  1708.     if (ea.argt & NOTADR)    /* e.g. :buffer 2, :sleep 3 */
  1709.     {
  1710.         ea.line2 = n;
  1711.         if (ea.addr_count == 0)
  1712.         ea.addr_count = 1;
  1713.     }
  1714.     else
  1715.     {
  1716.         ea.line1 = ea.line2;
  1717.         ea.line2 += n - 1;
  1718.         ++ea.addr_count;
  1719.         /*
  1720.          * Be vi compatible: no error message for out of range.
  1721.          */
  1722.         if (ea.line2 > curbuf->b_ml.ml_line_count)
  1723.         ea.line2 = curbuf->b_ml.ml_line_count;
  1724.     }
  1725.     }
  1726.                         /* no arguments allowed */
  1727.     if (!(ea.argt & EXTRA) && *ea.arg != NUL &&
  1728.                  vim_strchr((char_u *)"|\"", *ea.arg) == NULL)
  1729.     {
  1730.     errormsg = (char_u *)_(e_trailing);
  1731.     goto doend;
  1732.     }
  1733.  
  1734.     if ((ea.argt & NEEDARG) && *ea.arg == NUL)
  1735.     {
  1736.     errormsg = (char_u *)_(e_argreq);
  1737.     goto doend;
  1738.     }
  1739.  
  1740. #ifdef FEAT_EVAL
  1741.     /*
  1742.      * Skip the command when it's not going to be executed.
  1743.      * The commands like :if, :endif, etc. always need to be executed.
  1744.      * Also make an exception for commands that handle a trailing command
  1745.      * themselves.
  1746.      */
  1747.     if (ea.skip)
  1748.     {
  1749.     switch (ea.cmdidx)
  1750.     {
  1751.         /* commands that need evaluation */
  1752.         case CMD_while:
  1753.         case CMD_endwhile:
  1754.         case CMD_if:
  1755.         case CMD_elseif:
  1756.         case CMD_else:
  1757.         case CMD_endif:
  1758.         case CMD_function:
  1759.                 break;
  1760.  
  1761.         /* Commands that handle '|' themselves.  Check: A command should
  1762.          * either have the TRLBAR flag, appear in this list or appear in
  1763.          * the list at ":help :bar". */
  1764.         case CMD_aboveleft:
  1765.         case CMD_and:
  1766.         case CMD_belowright:
  1767.         case CMD_botright:
  1768.         case CMD_browse:
  1769.         case CMD_call:
  1770.         case CMD_confirm:
  1771.         case CMD_djump:
  1772.         case CMD_dlist:
  1773.         case CMD_dsearch:
  1774.         case CMD_dsplit:
  1775.         case CMD_echo:
  1776.         case CMD_echoerr:
  1777.         case CMD_echomsg:
  1778.         case CMD_echon:
  1779.         case CMD_execute:
  1780.         case CMD_help:
  1781.         case CMD_hide:
  1782.         case CMD_ijump:
  1783.         case CMD_ilist:
  1784.         case CMD_isearch:
  1785.         case CMD_isplit:
  1786.         case CMD_leftabove:
  1787.         case CMD_let:
  1788.         case CMD_match:
  1789.         case CMD_psearch:
  1790.         case CMD_return:
  1791.         case CMD_rightbelow:
  1792.         case CMD_silent:
  1793.         case CMD_smagic:
  1794.         case CMD_snomagic:
  1795.         case CMD_substitute:
  1796.         case CMD_syntax:
  1797.         case CMD_tilde:
  1798.         case CMD_topleft:
  1799.         case CMD_verbose:
  1800.         case CMD_vertical:
  1801.                 break;
  1802.  
  1803.         default:        goto doend;
  1804.     }
  1805.     }
  1806. #endif
  1807.  
  1808.     if (ea.argt & XFILE)
  1809.     {
  1810.     if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
  1811.         goto doend;
  1812.     }
  1813.  
  1814. #ifdef FEAT_LISTCMDS
  1815.     /*
  1816.      * Accept buffer name.  Cannot be used at the same time with a buffer
  1817.      * number.  Don't do this for a user command.
  1818.      */
  1819.     if ((ea.argt & BUFNAME) && *ea.arg != NUL && ea.addr_count == 0
  1820. # ifdef FEAT_USR_CMDS
  1821.         && !USER_CMDIDX(ea.cmdidx)
  1822. # endif
  1823.         )
  1824.     {
  1825.     /*
  1826.      * :bdelete, :bwipeout and :bunload take several arguments, separated
  1827.      * by spaces: find next space (skipping over escaped characters).
  1828.      * The others take one argument: ignore trailing spaces.
  1829.      */
  1830.     if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout
  1831.                           || ea.cmdidx == CMD_bunload)
  1832.         p = skiptowhite_esc(ea.arg);
  1833.     else
  1834.     {
  1835.         p = ea.arg + STRLEN(ea.arg);
  1836.         while (p > ea.arg && vim_iswhite(p[-1]))
  1837.         --p;
  1838.     }
  1839.     ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & BUFUNL) != 0, FALSE);
  1840.     if (ea.line2 < 0)        /* failed */
  1841.         goto doend;
  1842.     ea.addr_count = 1;
  1843.     ea.arg = skipwhite(p);
  1844.     }
  1845. #endif
  1846.  
  1847. /*
  1848.  * 6. switch on command name
  1849.  *
  1850.  * The "ea" structure holds the arguments that can be used.
  1851.  */
  1852.     ea.cmdlinep = cmdlinep;
  1853.     ea.getline = getline;
  1854.     ea.cookie = cookie;
  1855. #ifdef FEAT_EVAL
  1856.     ea.cstack = cstack;
  1857. #endif
  1858.  
  1859. #ifdef FEAT_USR_CMDS
  1860.     if (USER_CMDIDX(ea.cmdidx))
  1861.     {
  1862.     /*
  1863.      * Execute a user-defined command.
  1864.      */
  1865.     do_ucmd(&ea);
  1866.     }
  1867.     else
  1868. #endif
  1869.     {
  1870.     /*
  1871.      * Call the function to execute the command.
  1872.      */
  1873.     ea.errmsg = NULL;
  1874.     (cmdnames[ea.cmdidx].cmd_func)(&ea);
  1875.     if (ea.errmsg != NULL)
  1876.         errormsg = (char_u *)_(ea.errmsg);
  1877.     }
  1878.  
  1879. doend:
  1880.     if (curwin->w_cursor.lnum == 0)    /* can happen with zero line number */
  1881.     curwin->w_cursor.lnum = 1;
  1882.  
  1883.     if (verbose_save >= 0)
  1884.     p_verbose = verbose_save;
  1885.  
  1886.     cmdmod = save_cmdmod;
  1887.  
  1888.     if (did_silent > 0)
  1889.     {
  1890.     /* messages could be enabled for a serious error, need to check if the
  1891.      * counters don't become negative */
  1892.     msg_silent -= did_silent;
  1893.     if (msg_silent < 0)
  1894.         msg_silent = 0;
  1895.     emsg_silent -= did_esilent;
  1896.     if (emsg_silent < 0)
  1897.         emsg_silent = 0;
  1898.     /* Restore msg_scroll, it's set by file I/O commands, even when no
  1899.      * message is actually displayed. */
  1900.     msg_scroll = save_msg_scroll;
  1901.     }
  1902.  
  1903.     if (errormsg != NULL && *errormsg != NUL && !did_emsg)
  1904.     {
  1905.     if (sourcing)
  1906.     {
  1907.         if (errormsg != IObuff)
  1908.         {
  1909.         STRCPY(IObuff, errormsg);
  1910.         errormsg = IObuff;
  1911.         }
  1912.         STRCAT(errormsg, ": ");
  1913.         STRNCAT(errormsg, *cmdlinep, IOSIZE - STRLEN(IObuff));
  1914.     }
  1915.     emsg(errormsg);
  1916.     }
  1917.     if (ea.nextcmd && *ea.nextcmd == NUL)    /* not really a next command */
  1918.     ea.nextcmd = NULL;
  1919.  
  1920. #ifdef FEAT_EVAL
  1921.     --debug_level;
  1922. #endif
  1923.  
  1924.     return ea.nextcmd;
  1925. }
  1926. #if (_MSC_VER == 1200)
  1927. #pragma optimize( "", on )
  1928. #endif
  1929.  
  1930. /*
  1931.  * Check for a command modifier command with optional tail.
  1932.  * If there is a match advance "pp" to the argument and return TRUE.
  1933.  */
  1934.     static int
  1935. checkforcmd(pp, cmd, len)
  1936.     char_u    **pp;        /* start of command line */
  1937.     char    *cmd;        /* name of command */
  1938.     int        len;        /* required length */
  1939. {
  1940.     int        i;
  1941.  
  1942.     for (i = 0; cmd[i] != NUL; ++i)
  1943.     if (cmd[i] != (*pp)[i])
  1944.         break;
  1945.     if (i >= len && !isalpha((*pp)[i]))
  1946.     {
  1947.     *pp = skipwhite(*pp + i);
  1948.     return TRUE;
  1949.     }
  1950.     return FALSE;
  1951. }
  1952.  
  1953. /*
  1954.  * Find an Ex command by its name, either built-in or user.
  1955.  * Name can be found at eap->cmd.
  1956.  * Returns pointer to char after the command name.
  1957.  * Returns NULL for an ambiguous user command.
  1958.  */
  1959. /*ARGSUSED*/
  1960.     static char_u *
  1961. find_command(eap, full)
  1962.     exarg_T    *eap;
  1963.     int        *full;
  1964. {
  1965.     int        len;
  1966.     char_u    *p;
  1967.  
  1968.     /*
  1969.      * Isolate the command and search for it in the command table.
  1970.      * Exeptions:
  1971.      * - the 'k' command can directly be followed by any character.
  1972.      * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
  1973.      *        but :sre[wind] is another command, as are :scrip[tnames],
  1974.      *        :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
  1975.      */
  1976.     p = eap->cmd;
  1977.     if (*p == 'k')
  1978.     {
  1979.     eap->cmdidx = CMD_k;
  1980.     ++p;
  1981.     }
  1982.     else if (p[0] == 's'
  1983.         && ((p[1] == 'c' && p[2] != 's' && p[2] != 'r' && p[3] != 'i' && p[4] != 'p')
  1984.         || p[1] == 'g'
  1985.         || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g')
  1986.         || p[1] == 'I'
  1987.         || (p[1] == 'r' && p[2] != 'e')))
  1988.     {
  1989.     eap->cmdidx = CMD_substitute;
  1990.     ++p;
  1991.     }
  1992.     else
  1993.     {
  1994.     while (ASCII_ISALPHA(*p))
  1995.         ++p;
  1996.     /* check for non-alpha command */
  1997.     if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
  1998.         ++p;
  1999.     len = (int)(p - eap->cmd);
  2000.  
  2001.     if (ASCII_ISLOWER(*eap->cmd))
  2002.         eap->cmdidx = cmdidxs[CharOrdLow(*eap->cmd)];
  2003.     else
  2004.         eap->cmdidx = cmdidxs[26];
  2005.  
  2006.     for ( ; (int)eap->cmdidx < (int)CMD_SIZE;
  2007.                    eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1))
  2008.         if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd,
  2009.                                 (size_t)len) == 0)
  2010.         {
  2011. #ifdef FEAT_EVAL
  2012.         if (full != NULL
  2013.                && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL)
  2014.             *full = TRUE;
  2015. #endif
  2016.         break;
  2017.         }
  2018.  
  2019. #ifdef FEAT_USR_CMDS
  2020.     /* Look for a user defined command as a last resort */
  2021.     if (eap->cmdidx == CMD_SIZE && *eap->cmd >= 'A' && *eap->cmd <= 'Z')
  2022.     {
  2023.         ucmd_T    *cmd;
  2024.         int        j, k, matchlen = 0;
  2025.         int        found = FALSE, possible = FALSE;
  2026.         char_u    *cp, *np;    /* Point into typed cmd and test name */
  2027.         garray_T    *gap;
  2028.  
  2029.         /* User defined commands may contain numbers */
  2030.         while (ASCII_ISALNUM(*p))
  2031.         ++p;
  2032.         len = (int)(p - eap->cmd);
  2033.  
  2034.         /*
  2035.          * Look for buffer-local user commands first, then global ones.
  2036.          */
  2037.         gap = &curbuf->b_ucmds;
  2038.         for (;;)
  2039.         {
  2040.         cmd = USER_CMD_GA(gap, 0);
  2041.  
  2042.         for (j = 0; j < gap->ga_len; ++j, ++cmd)
  2043.         {
  2044.             cp = eap->cmd;
  2045.             np = cmd->uc_name;
  2046.             k = 0;
  2047.             while (k < len && *np != NUL && *cp++ == *np++)
  2048.             k++;
  2049.             if (k == len || (*np == NUL && isdigit(eap->cmd[k])))
  2050.             {
  2051.             if (k == len && found)
  2052.                 return NULL;
  2053.  
  2054.             if (!found)
  2055.             {
  2056.                 /* If we matched up to a digit, then there could
  2057.                  * be another command including the digit that we
  2058.                  * should use instead.
  2059.                  */
  2060.                 if (k == len)
  2061.                 found = TRUE;
  2062.                 else
  2063.                 possible = TRUE;
  2064.  
  2065.                 if (gap == &ucmds)
  2066.                 eap->cmdidx = CMD_USER;
  2067.                 else
  2068.                 eap->cmdidx = CMD_USER_BUF;
  2069.                 eap->argt = cmd->uc_argt;
  2070.                 eap->useridx = j;
  2071.  
  2072.                 /* Do not search for further abbreviations
  2073.                  * if this is an exact match
  2074.                  */
  2075.                 matchlen = k;
  2076.                 if (k == len && *np == NUL)
  2077.                 {
  2078.                 if (full != NULL)
  2079.                     *full = TRUE;
  2080.                 break;
  2081.                 }
  2082.             }
  2083.             }
  2084.         }
  2085.  
  2086.         /* Stop if we found a match of searched all. */
  2087.         if (j < gap->ga_len || gap == &ucmds)
  2088.             break;
  2089.         gap = &ucmds;
  2090.         }
  2091.  
  2092.         /* The match we found may be followed immediately by a
  2093.          * number.  Move *p back to point to it.
  2094.          */
  2095.         if (found || possible)
  2096.         p += matchlen - len;
  2097.     }
  2098. #endif
  2099.  
  2100.     if (len == 0)
  2101.         eap->cmdidx = CMD_SIZE;
  2102.     }
  2103.  
  2104.     return p;
  2105. }
  2106.  
  2107. #if defined(FEAT_EVAL) || defined(PROTO)
  2108. /*
  2109.  * Return > 0 if an Ex command "name" exists.
  2110.  * Return 2 if there is an exact match.
  2111.  * Return 3 if there is an ambiguous match.
  2112.  */
  2113.     int
  2114. cmd_exists(name)
  2115.     char_u    *name;
  2116. {
  2117.     exarg_T    ea;
  2118.     int        full = FALSE;
  2119.  
  2120.     ea.cmd = name;
  2121.     ea.cmdidx = (cmdidx_T)0;
  2122.     if (find_command(&ea, &full) == NULL)
  2123.     return 3;
  2124.     return (ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1));
  2125. }
  2126. #endif
  2127.  
  2128. /*
  2129.  * This is all pretty much copied from do_one_cmd(), with all the extra stuff
  2130.  * we don't need/want deleted.    Maybe this could be done better if we didn't
  2131.  * repeat all this stuff.  The only problem is that they may not stay
  2132.  * perfectly compatible with each other, but then the command line syntax
  2133.  * probably won't change that much -- webb.
  2134.  */
  2135.     char_u *
  2136. set_one_cmd_context(xp, buff)
  2137.     expand_T    *xp;
  2138.     char_u    *buff;        /* buffer for command string */
  2139. {
  2140.     char_u        *p;
  2141.     char_u        *cmd, *arg;
  2142.     int            i = 0;
  2143.     cmdidx_T        cmdidx;
  2144.     long_u        argt = 0;
  2145. #if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)
  2146.     int            compl = EXPAND_NOTHING;
  2147. #endif
  2148. #ifdef FEAT_CMDL_COMPL
  2149.     int            delim;
  2150. #endif
  2151.     int            forceit = FALSE;
  2152.     int            usefilter = FALSE;  /* filter instead of file name */
  2153.  
  2154.     xp->xp_pattern = buff;
  2155.     xp->xp_context = EXPAND_COMMANDS;    /* Default until we get past command */
  2156.     xp->xp_set_path = FALSE;
  2157.  
  2158. /*
  2159.  * 2. skip comment lines and leading space, colons or bars
  2160.  */
  2161.     for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
  2162.     ;
  2163.     xp->xp_pattern = cmd;
  2164.  
  2165.     if (*cmd == NUL)
  2166.     return NULL;
  2167.     if (*cmd == '"')        /* ignore comment lines */
  2168.     {
  2169.     xp->xp_context = EXPAND_NOTHING;
  2170.     return NULL;
  2171.     }
  2172.  
  2173. /*
  2174.  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  2175.  */
  2176.     cmd = skip_range(cmd, &xp->xp_context);
  2177.  
  2178. /*
  2179.  * 4. parse command
  2180.  */
  2181.  
  2182.     cmd = skipwhite(cmd);
  2183.     xp->xp_pattern = cmd;
  2184.     if (*cmd == NUL)
  2185.     return NULL;
  2186.     if (*cmd == '"')
  2187.     {
  2188.     xp->xp_context = EXPAND_NOTHING;
  2189.     return NULL;
  2190.     }
  2191.  
  2192.     if (*cmd == '|' || *cmd == '\n')
  2193.     return cmd + 1;            /* There's another command */
  2194.  
  2195.     /*
  2196.      * Isolate the command and search for it in the command table.
  2197.      * Exceptions:
  2198.      * - the 'k' command can directly be followed by any character.
  2199.      * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
  2200.      */
  2201.     if (*cmd == 'k')
  2202.     {
  2203.     cmdidx = CMD_k;
  2204.     p = cmd + 1;
  2205.     }
  2206.     else
  2207.     {
  2208.     p = cmd;
  2209.     while (ASCII_ISALPHA(*p) || *p == '*')    /* Allow * wild card */
  2210.         ++p;
  2211.     /* check for non-alpha command */
  2212.     if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
  2213.         ++p;
  2214.     i = (int)(p - cmd);
  2215.  
  2216.     if (i == 0)
  2217.     {
  2218.         xp->xp_context = EXPAND_UNSUCCESSFUL;
  2219.         return NULL;
  2220.     }
  2221.     for (cmdidx = (cmdidx_T)0; (int)cmdidx < (int)CMD_SIZE;
  2222.                      cmdidx = (cmdidx_T)((int)cmdidx + 1))
  2223.         if (STRNCMP(cmdnames[(int)cmdidx].cmd_name, cmd, (size_t)i) == 0)
  2224.         break;
  2225. #ifdef FEAT_USR_CMDS
  2226.  
  2227.     if (cmd[0] >= 'A' && cmd[0] <= 'Z')
  2228.     {
  2229.         while (ASCII_ISALNUM(*p) || *p == '*')    /* Allow * wild card */
  2230.         ++p;
  2231.         i = (int)(p - cmd);
  2232.     }
  2233. #endif
  2234.     }
  2235.  
  2236.     /*
  2237.      * If the cursor is touching the command, and it ends in an alpha-numeric
  2238.      * character, complete the command name.
  2239.      */
  2240.     if (*p == NUL && ASCII_ISALNUM(p[-1]))
  2241.     return NULL;
  2242.  
  2243.     if (cmdidx == CMD_SIZE)
  2244.     {
  2245.     if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL)
  2246.     {
  2247.         cmdidx = CMD_substitute;
  2248.         p = cmd + 1;
  2249.     }
  2250. #ifdef FEAT_USR_CMDS
  2251.     else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
  2252.     {
  2253.         /* Look for a user defined command as a last resort */
  2254.         ucmd_T    *uc;
  2255.         int        j, k, matchlen = 0;
  2256.         int        found = FALSE, possible = FALSE;
  2257.         char_u    *cp, *np;    /* Point into typed cmd and test name */
  2258.         garray_T    *gap;
  2259.  
  2260.         gap = &curbuf->b_ucmds;
  2261.         for (;;)
  2262.         {
  2263.         uc = USER_CMD_GA(gap, 0);
  2264.         for (j = 0; j < gap->ga_len; ++j, ++uc)
  2265.         {
  2266.             cp = cmd;
  2267.             np = uc->uc_name;
  2268.             k = 0;
  2269.             while (k < i && *np != NUL && *cp++ == *np++)
  2270.             k++;
  2271.             if (k == i || (*np == NUL && isdigit(cmd[k])))
  2272.             {
  2273.             if (k == i && found)
  2274.             {
  2275.                 /* Ambiguous abbreviation */
  2276.                 xp->xp_context = EXPAND_UNSUCCESSFUL;
  2277.                 return NULL;
  2278.             }
  2279.             if (!found)
  2280.             {
  2281.                 /* If we matched up to a digit, then there could
  2282.                  * be another command including the digit that we
  2283.                  * should use instead.
  2284.                  */
  2285.                 if (k == i)
  2286.                 found = TRUE;
  2287.                 else
  2288.                 possible = TRUE;
  2289.  
  2290.                 if (gap == &ucmds)
  2291.                 cmdidx = CMD_USER;
  2292.                 else
  2293.                 cmdidx = CMD_USER_BUF;
  2294.                 argt = uc->uc_argt;
  2295. #ifdef FEAT_CMDL_COMPL
  2296.                 compl = uc->uc_compl;
  2297. #endif
  2298.                 /* Do not search for further abbreviations
  2299.                  * if this is an exact match
  2300.                  */
  2301.                 matchlen = k;
  2302.                 if (k == i && *np == NUL)
  2303.                 break;
  2304.             }
  2305.             }
  2306.         }
  2307.         if (gap == &ucmds || j < gap->ga_len)
  2308.             break;
  2309.         gap = &ucmds;
  2310.         }
  2311.  
  2312.         /* The match we found may be followed immediately by a
  2313.          * number.  Move *p back to point to it.
  2314.          */
  2315.         if (found || possible)
  2316.         p += matchlen - i;
  2317.     }
  2318. #endif
  2319.     }
  2320.     if (cmdidx == CMD_SIZE)
  2321.     {
  2322.     /* Not still touching the command and it was an illegal one */
  2323.     xp->xp_context = EXPAND_UNSUCCESSFUL;
  2324.     return NULL;
  2325.     }
  2326.  
  2327.     xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */
  2328.  
  2329.     if (*p == '!')            /* forced commands */
  2330.     {
  2331.     forceit = TRUE;
  2332.     ++p;
  2333.     }
  2334.  
  2335. /*
  2336.  * 5. parse arguments
  2337.  */
  2338. #ifdef FEAT_USR_CMDS
  2339.     if (!USER_CMDIDX(cmdidx))
  2340. #endif
  2341.     argt = cmdnames[(int)cmdidx].cmd_argt;
  2342.  
  2343.     arg = skipwhite(p);
  2344.  
  2345.     if (cmdidx == CMD_write || cmdidx == CMD_update)
  2346.     {
  2347.     if (*arg == '>')            /* append */
  2348.     {
  2349.         if (*++arg == '>')
  2350.         ++arg;
  2351.         arg = skipwhite(arg);
  2352.     }
  2353.     else if (*arg == '!' && cmdidx == CMD_write)    /* :w !filter */
  2354.     {
  2355.         ++arg;
  2356.         usefilter = TRUE;
  2357.     }
  2358.     }
  2359.  
  2360.     if (cmdidx == CMD_read)
  2361.     {
  2362.     usefilter = forceit;            /* :r! filter if forced */
  2363.     if (*arg == '!')            /* :r !filter */
  2364.     {
  2365.         ++arg;
  2366.         usefilter = TRUE;
  2367.     }
  2368.     }
  2369.  
  2370.     if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
  2371.     {
  2372.     while (*arg == *cmd)        /* allow any number of '>' or '<' */
  2373.         ++arg;
  2374.     arg = skipwhite(arg);
  2375.     }
  2376.  
  2377.     /* Does command allow "+command"? */
  2378.     if ((argt & EDITCMD) && !usefilter && *arg == '+')
  2379.     {
  2380.     /* Check if we're in the +command */
  2381.     p = arg + 1;
  2382.     arg = skip_cmd_arg(arg);
  2383.  
  2384.     /* Still touching the command after '+'? */
  2385.     if (*arg == NUL)
  2386.         return p;
  2387.  
  2388.     /* Skip space(s) after +command to get to the real argument */
  2389.     arg = skipwhite(arg);
  2390.     }
  2391.  
  2392.     /*
  2393.      * Check for '|' to separate commands and '"' to start comments.
  2394.      * Don't do this for ":read !cmd" and ":write !cmd".
  2395.      */
  2396.     if ((argt & TRLBAR) && !usefilter)
  2397.     {
  2398.     p = arg;
  2399.     /* ":redir @" is not the start of a comment */
  2400.     if (cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
  2401.         p += 2;
  2402.     while (*p)
  2403.     {
  2404.         if (*p == Ctrl_V)
  2405.         {
  2406.         if (p[1] != NUL)
  2407.             ++p;
  2408.         }
  2409.         else if ( (*p == '"' && !(argt & NOTRLCOM))
  2410.             || *p == '|' || *p == '\n')
  2411.         {
  2412.         if (*(p - 1) != '\\')
  2413.         {
  2414.             if (*p == '|' || *p == '\n')
  2415.             return p + 1;
  2416.             return NULL;    /* It's a comment */
  2417.         }
  2418.         }
  2419.         ++p;
  2420.     }
  2421.     }
  2422.  
  2423.                         /* no arguments allowed */
  2424.     if (!(argt & EXTRA) && *arg != NUL &&
  2425.                     vim_strchr((char_u *)"|\"", *arg) == NULL)
  2426.     return NULL;
  2427.  
  2428.     /* Find start of last argument (argument just before cursor): */
  2429.     p = buff + STRLEN(buff);
  2430.     while (p != arg && *p != ' ' && *p != TAB)
  2431.     p--;
  2432.     if (*p == ' ' || *p == TAB)
  2433.     p++;
  2434.     xp->xp_pattern = p;
  2435.  
  2436.     if (argt & XFILE)
  2437.     {
  2438.     int in_quote = FALSE;
  2439.     char_u *bow = NULL;    /* Beginning of word */
  2440.  
  2441.     /*
  2442.      * Allow spaces within back-quotes to count as part of the argument
  2443.      * being expanded.
  2444.      */
  2445.     xp->xp_pattern = skipwhite(arg);
  2446.     for (p = xp->xp_pattern; *p; )
  2447.     {
  2448.         if (*p == '\\' && p[1])
  2449.         ++p;
  2450. #ifdef SPACE_IN_FILENAME
  2451.         else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
  2452. #else
  2453.         else if (vim_iswhite(*p))
  2454. #endif
  2455.         {
  2456.         p = skipwhite(p);
  2457.         if (in_quote)
  2458.             bow = p;
  2459.         else
  2460.             xp->xp_pattern = p;
  2461.         --p;
  2462.         }
  2463.         else if (*p == '`')
  2464.         {
  2465.         if (!in_quote)
  2466.         {
  2467.             xp->xp_pattern = p;
  2468.             bow = p + 1;
  2469.         }
  2470.         in_quote = !in_quote;
  2471.         }
  2472. #ifdef FEAT_MBYTE
  2473.         if (has_mbyte)
  2474.         p += (*mb_ptr2len_check)(p);
  2475.         else
  2476. #endif
  2477.         ++p;
  2478.     }
  2479.  
  2480.     /*
  2481.      * If we are still inside the quotes, and we passed a space, just
  2482.      * expand from there.
  2483.      */
  2484.     if (bow != NULL && in_quote)
  2485.         xp->xp_pattern = bow;
  2486.     xp->xp_context = EXPAND_FILES;
  2487.  
  2488.     /* Check for environment variable */
  2489.     if (*xp->xp_pattern == '$'
  2490. #if defined(MSDOS) || defined(MSWIN) || defined(OS2)
  2491.         || *xp->xp_pattern == '%'
  2492. #endif
  2493.         )
  2494.     {
  2495.         for (p = xp->xp_pattern + 1; *p != NUL; ++p)
  2496.         if (!vim_isIDc(*p))
  2497.             break;
  2498.         if (*p == NUL)
  2499.         {
  2500.         xp->xp_context = EXPAND_ENV_VARS;
  2501.         ++xp->xp_pattern;
  2502.         }
  2503.     }
  2504.     }
  2505.  
  2506. /*
  2507.  * 6. switch on command name
  2508.  */
  2509.     switch (cmdidx)
  2510.     {
  2511.     case CMD_cd:
  2512.     case CMD_chdir:
  2513.         if (xp->xp_context == EXPAND_FILES)
  2514.         xp->xp_context = EXPAND_DIRECTORIES;
  2515.         break;
  2516.     case CMD_help:
  2517.         xp->xp_context = EXPAND_HELP;
  2518.         xp->xp_pattern = arg;
  2519.         break;
  2520.  
  2521.     /* Command modifiers: return the argument. */
  2522.     case CMD_aboveleft:
  2523.     case CMD_belowright:
  2524.     case CMD_botright:
  2525.     case CMD_browse:
  2526.     case CMD_confirm:
  2527.     case CMD_folddoclosed:
  2528.     case CMD_folddoopen:
  2529.     case CMD_hide:
  2530.     case CMD_leftabove:
  2531.     case CMD_rightbelow:
  2532.     case CMD_silent:
  2533.     case CMD_topleft:
  2534.     case CMD_verbose:
  2535.     case CMD_vertical:
  2536.         return arg;
  2537.  
  2538. #ifdef FEAT_SEARCH_EXTRA
  2539.     case CMD_match:
  2540.         if (*arg == NUL || !ends_excmd(*arg))
  2541.         {
  2542.         /* Dummy call to clear variables. */
  2543.         set_context_in_highlight_cmd(xp, (char_u *)"link n");
  2544.         xp->xp_context = EXPAND_HIGHLIGHT;
  2545.         xp->xp_pattern = arg;
  2546.         arg = skipwhite(skiptowhite(arg));
  2547.         if (*arg != NUL)
  2548.         {
  2549.             xp->xp_context = EXPAND_NOTHING;
  2550.             arg = skip_regexp(arg + 1, *arg, p_magic);
  2551.         }
  2552.         }
  2553.         return find_nextcmd(arg);
  2554. #endif
  2555.  
  2556. #ifdef FEAT_CMDL_COMPL
  2557. /*
  2558.  * All completion for the +cmdline_compl feature goes here.
  2559.  */
  2560.  
  2561. # ifdef FEAT_USR_CMDS
  2562.     case CMD_command:
  2563.         /* Check for attributes */
  2564.         while (*arg == '-')
  2565.         {
  2566.         arg++;        /* Skip "-" */
  2567.         p = skiptowhite(arg);
  2568.         if (*p == NUL)
  2569.         {
  2570.             /* Cursor is still in the attribute */
  2571.             p = vim_strchr(arg, '=');
  2572.             if (p == NULL)
  2573.             {
  2574.             /* No "=", so complete attribute names */
  2575.             xp->xp_context = EXPAND_USER_CMD_FLAGS;
  2576.             xp->xp_pattern = arg;
  2577.             return NULL;
  2578.             }
  2579.  
  2580.             /* For the -complete and -nargs attributes, we complete
  2581.              * their arguments as well.
  2582.              */
  2583.             if (STRNICMP(arg, "complete", p - arg) == 0)
  2584.             {
  2585.             xp->xp_context = EXPAND_USER_COMPLETE;
  2586.             xp->xp_pattern = p + 1;
  2587.             return NULL;
  2588.             }
  2589.             else if (STRNICMP(arg, "nargs", p - arg) == 0)
  2590.             {
  2591.             xp->xp_context = EXPAND_USER_NARGS;
  2592.             xp->xp_pattern = p + 1;
  2593.             return NULL;
  2594.             }
  2595.             return NULL;
  2596.         }
  2597.         arg = skipwhite(p);
  2598.         }
  2599.  
  2600.         /* After the attributes comes the new command name */
  2601.         p = skiptowhite(arg);
  2602.         if (*p == NUL)
  2603.         {
  2604.         xp->xp_context = EXPAND_USER_COMMANDS;
  2605.         xp->xp_pattern = arg;
  2606.         break;
  2607.         }
  2608.  
  2609.         /* And finally comes a normal command */
  2610.         return skipwhite(p);
  2611.  
  2612.     case CMD_delcommand:
  2613.         xp->xp_context = EXPAND_USER_COMMANDS;
  2614.         xp->xp_pattern = arg;
  2615.         break;
  2616. # endif
  2617.  
  2618.     case CMD_global:
  2619.     case CMD_vglobal:
  2620.         delim = *arg;        /* get the delimiter */
  2621.         if (delim)
  2622.         ++arg;            /* skip delimiter if there is one */
  2623.  
  2624.         while (arg[0] != NUL && arg[0] != delim)
  2625.         {
  2626.         if (arg[0] == '\\' && arg[1] != NUL)
  2627.             ++arg;
  2628.         ++arg;
  2629.         }
  2630.         if (arg[0] != NUL)
  2631.         return arg + 1;
  2632.         break;
  2633.     case CMD_and:
  2634.     case CMD_substitute:
  2635.         delim = *arg;
  2636.         if (delim)
  2637.         {
  2638.         /* skip "from" part */
  2639.         ++arg;
  2640.         arg = skip_regexp(arg, delim, p_magic);
  2641.         }
  2642.         /* skip "to" part */
  2643.         while (arg[0] != NUL && arg[0] != delim)
  2644.         {
  2645.         if (arg[0] == '\\' && arg[1] != NUL)
  2646.             ++arg;
  2647.         ++arg;
  2648.         }
  2649.         if (arg[0] != NUL)    /* skip delimiter */
  2650.         ++arg;
  2651.         while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
  2652.         ++arg;
  2653.         if (arg[0] != NUL)
  2654.         return arg;
  2655.         break;
  2656.     case CMD_isearch:
  2657.     case CMD_dsearch:
  2658.     case CMD_ilist:
  2659.     case CMD_dlist:
  2660.     case CMD_ijump:
  2661.     case CMD_psearch:
  2662.     case CMD_djump:
  2663.     case CMD_isplit:
  2664.     case CMD_dsplit:
  2665.         arg = skipwhite(skipdigits(arg));        /* skip count */
  2666.         if (*arg == '/')    /* Match regexp, not just whole words */
  2667.         {
  2668.         for (++arg; *arg && *arg != '/'; arg++)
  2669.             if (*arg == '\\' && arg[1] != NUL)
  2670.             arg++;
  2671.         if (*arg)
  2672.         {
  2673.             arg = skipwhite(arg + 1);
  2674.  
  2675.             /* Check for trailing illegal characters */
  2676.             if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
  2677.             xp->xp_context = EXPAND_NOTHING;
  2678.             else
  2679.             return arg;
  2680.         }
  2681.         }
  2682.         break;
  2683. #ifdef FEAT_AUTOCMD
  2684.     case CMD_autocmd:
  2685.         return set_context_in_autocmd(xp, arg, FALSE);
  2686.  
  2687.     case CMD_doautocmd:
  2688.         return set_context_in_autocmd(xp, arg, TRUE);
  2689. #endif
  2690.     case CMD_set:
  2691.         set_context_in_set_cmd(xp, arg, 0);
  2692.         break;
  2693.     case CMD_setglobal:
  2694.         set_context_in_set_cmd(xp, arg, OPT_GLOBAL);
  2695.         break;
  2696.     case CMD_setlocal:
  2697.         set_context_in_set_cmd(xp, arg, OPT_LOCAL);
  2698.         break;
  2699.     case CMD_tag:
  2700.     case CMD_stag:
  2701.     case CMD_ptag:
  2702.     case CMD_tselect:
  2703.     case CMD_stselect:
  2704.     case CMD_ptselect:
  2705.     case CMD_tjump:
  2706.     case CMD_stjump:
  2707.     case CMD_ptjump:
  2708.         xp->xp_context = EXPAND_TAGS;
  2709.         xp->xp_pattern = arg;
  2710.         break;
  2711.     case CMD_augroup:
  2712.         xp->xp_context = EXPAND_AUGROUP;
  2713.         xp->xp_pattern = arg;
  2714.         break;
  2715. #ifdef FEAT_SYN_HL
  2716.     case CMD_syntax:
  2717.         set_context_in_syntax_cmd(xp, arg);
  2718.         break;
  2719. #endif
  2720. #ifdef FEAT_EVAL
  2721.     case CMD_let:
  2722.     case CMD_if:
  2723.     case CMD_elseif:
  2724.     case CMD_while:
  2725.     case CMD_echo:
  2726.     case CMD_echon:
  2727.     case CMD_execute:
  2728.     case CMD_echomsg:
  2729.     case CMD_echoerr:
  2730.     case CMD_call:
  2731.     case CMD_return:
  2732.         set_context_for_expression(xp, arg, cmdidx);
  2733.         break;
  2734.  
  2735.     case CMD_unlet:
  2736.         while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
  2737.         arg = xp->xp_pattern + 1;
  2738.         xp->xp_context = EXPAND_USER_VARS;
  2739.         xp->xp_pattern = arg;
  2740.         break;
  2741.  
  2742.     case CMD_function:
  2743.     case CMD_delfunction:
  2744.         xp->xp_context = EXPAND_USER_FUNC;
  2745.         xp->xp_pattern = arg;
  2746.         break;
  2747.  
  2748.     case CMD_echohl:
  2749.         xp->xp_context = EXPAND_HIGHLIGHT;
  2750.         xp->xp_pattern = arg;
  2751.         break;
  2752. #endif
  2753.     case CMD_highlight:
  2754.         set_context_in_highlight_cmd(xp, arg);
  2755.         break;
  2756. #ifdef FEAT_LISTCMDS
  2757.     case CMD_bdelete:
  2758.     case CMD_bwipeout:
  2759.     case CMD_bunload:
  2760.         while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
  2761.         arg = xp->xp_pattern + 1;
  2762.         /*FALLTHROUGH*/
  2763.     case CMD_buffer:
  2764.     case CMD_sbuffer:
  2765.     case CMD_checktime:
  2766.         xp->xp_context = EXPAND_BUFFERS;
  2767.         xp->xp_pattern = arg;
  2768.         break;
  2769. #endif
  2770. #ifdef FEAT_USR_CMDS
  2771.     case CMD_USER:
  2772.     case CMD_USER_BUF:
  2773.         /* XFILE: file names are handled above */
  2774.         if (compl != EXPAND_NOTHING && !(argt & XFILE))
  2775.         {
  2776. # ifdef FEAT_MENU
  2777.         if (compl == EXPAND_MENUS)
  2778.             return set_context_in_menu_cmd(xp, cmd, arg, forceit);
  2779. # endif
  2780.         if (compl == EXPAND_COMMANDS)
  2781.             return arg;
  2782.         while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
  2783.             arg = xp->xp_pattern + 1;
  2784.         xp->xp_context = compl;
  2785.         xp->xp_pattern = arg;
  2786.         }
  2787.         break;
  2788. #endif
  2789.     case CMD_map:        case CMD_noremap:
  2790.     case CMD_nmap:        case CMD_nnoremap:
  2791.     case CMD_vmap:        case CMD_vnoremap:
  2792.     case CMD_omap:        case CMD_onoremap:
  2793.     case CMD_imap:        case CMD_inoremap:
  2794.     case CMD_cmap:        case CMD_cnoremap:
  2795.         return set_context_in_map_cmd(xp, cmd, arg, forceit,
  2796.                             FALSE, FALSE, cmdidx);
  2797.     case CMD_unmap:
  2798.     case CMD_nunmap:
  2799.     case CMD_vunmap:
  2800.     case CMD_ounmap:
  2801.     case CMD_iunmap:
  2802.     case CMD_cunmap:
  2803.         return set_context_in_map_cmd(xp, cmd, arg, forceit,
  2804.                              FALSE, TRUE, cmdidx);
  2805.     case CMD_abbreviate:    case CMD_noreabbrev:
  2806.     case CMD_cabbrev:    case CMD_cnoreabbrev:
  2807.     case CMD_iabbrev:    case CMD_inoreabbrev:
  2808.         return set_context_in_map_cmd(xp, cmd, arg, forceit,
  2809.                              TRUE, FALSE, cmdidx);
  2810.     case CMD_unabbreviate:
  2811.     case CMD_cunabbrev:
  2812.     case CMD_iunabbrev:
  2813.         return set_context_in_map_cmd(xp, cmd, arg, forceit,
  2814.                               TRUE, TRUE, cmdidx);
  2815. #ifdef FEAT_MENU
  2816.     case CMD_menu:        case CMD_noremenu:        case CMD_unmenu:
  2817.     case CMD_amenu:        case CMD_anoremenu:        case CMD_aunmenu:
  2818.     case CMD_nmenu:        case CMD_nnoremenu:        case CMD_nunmenu:
  2819.     case CMD_vmenu:        case CMD_vnoremenu:        case CMD_vunmenu:
  2820.     case CMD_omenu:        case CMD_onoremenu:        case CMD_ounmenu:
  2821.     case CMD_imenu:        case CMD_inoremenu:        case CMD_iunmenu:
  2822.     case CMD_cmenu:        case CMD_cnoremenu:        case CMD_cunmenu:
  2823.     case CMD_tmenu:                    case CMD_tunmenu:
  2824.     case CMD_popup:        case CMD_tearoff:        case CMD_emenu:
  2825.         return set_context_in_menu_cmd(xp, cmd, arg, forceit);
  2826. #endif
  2827.  
  2828.     case CMD_colorscheme:
  2829.         xp->xp_context = EXPAND_COLORS;
  2830.         xp->xp_pattern = arg;
  2831.         break;
  2832.  
  2833.     case CMD_compiler:
  2834.         xp->xp_context = EXPAND_COMPILER;
  2835.         xp->xp_pattern = arg;
  2836.         break;
  2837.  
  2838. #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
  2839.     && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
  2840.     case CMD_language:
  2841.         if (*skiptowhite(arg) == NUL)
  2842.         {
  2843.         xp->xp_context = EXPAND_LANGUAGE;
  2844.         xp->xp_pattern = arg;
  2845.         }
  2846.         else
  2847.         xp->xp_context = EXPAND_NOTHING;
  2848.         break;
  2849. #endif
  2850.  
  2851. #endif /* FEAT_CMDL_COMPL */
  2852.  
  2853.     default:
  2854.         break;
  2855.     }
  2856.     return NULL;
  2857. }
  2858.  
  2859. /*
  2860.  * skip a range specifier of the form: addr [,addr] [;addr] ..
  2861.  *
  2862.  * Backslashed delimiters after / or ? will be skipped, and commands will
  2863.  * not be expanded between /'s and ?'s or after "'".
  2864.  *
  2865.  * Returns the "cmd" pointer advanced to beyond the range.
  2866.  */
  2867.     char_u *
  2868. skip_range(cmd, ctx)
  2869.     char_u    *cmd;
  2870.     int        *ctx;    /* pointer to xp_context or NULL */
  2871. {
  2872.     int        delim;
  2873.  
  2874.     while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
  2875.                 vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
  2876.     {
  2877.     if (*cmd == '\'')
  2878.     {
  2879.         if (*++cmd == NUL && ctx != NULL)
  2880.         *ctx = EXPAND_NOTHING;
  2881.     }
  2882.     else if (*cmd == '/' || *cmd == '?')
  2883.     {
  2884.         delim = *cmd++;
  2885.         while (*cmd != NUL && *cmd != delim)
  2886.         if (*cmd++ == '\\' && *cmd != NUL)
  2887.             ++cmd;
  2888.         if (*cmd == NUL && ctx != NULL)
  2889.         *ctx = EXPAND_NOTHING;
  2890.     }
  2891.     if (*cmd != NUL)
  2892.         ++cmd;
  2893.     }
  2894.     return cmd;
  2895. }
  2896.  
  2897. /*
  2898.  * get a single EX address
  2899.  *
  2900.  * Set ptr to the next character after the part that was interpreted.
  2901.  * Set ptr to NULL when an error is encountered.
  2902.  *
  2903.  * Return MAXLNUM when no Ex address was found.
  2904.  */
  2905.     static linenr_T
  2906. get_address(ptr, skip)
  2907.     char_u    **ptr;
  2908.     int        skip;        /* only skip the address, don't use it */
  2909. {
  2910.     int        c;
  2911.     int        i;
  2912.     long    n;
  2913.     char_u    *cmd;
  2914.     pos_T    pos;
  2915.     pos_T    *fp;
  2916.     linenr_T    lnum;
  2917.  
  2918.     cmd = skipwhite(*ptr);
  2919.     lnum = MAXLNUM;
  2920.     do
  2921.     {
  2922.     switch (*cmd)
  2923.     {
  2924.         case '.':                /* '.' - Cursor position */
  2925.             ++cmd;
  2926.             lnum = curwin->w_cursor.lnum;
  2927.             break;
  2928.  
  2929.         case '$':                /* '$' - last line */
  2930.             ++cmd;
  2931.             lnum = curbuf->b_ml.ml_line_count;
  2932.             break;
  2933.  
  2934.         case '\'':                /* ''' - mark */
  2935.             if (*++cmd == NUL)
  2936.             {
  2937.                 cmd = NULL;
  2938.                 goto error;
  2939.             }
  2940.             if (skip)
  2941.                 ++cmd;
  2942.             else
  2943.             {
  2944.                 fp = getmark(*cmd, FALSE);
  2945.                 ++cmd;
  2946.                 if (check_mark(fp) == FAIL)
  2947.                 {
  2948.                 cmd = NULL;
  2949.                 goto error;
  2950.                 }
  2951.                 lnum = fp->lnum;
  2952.             }
  2953.             break;
  2954.  
  2955.         case '/':
  2956.         case '?':            /* '/' or '?' - search */
  2957.             c = *cmd++;
  2958.             if (skip)    /* skip "/pat/" */
  2959.             {
  2960.                 cmd = skip_regexp(cmd, c, (int)p_magic);
  2961.                 if (*cmd == c)
  2962.                 ++cmd;
  2963.             }
  2964.             else
  2965.             {
  2966.                 pos = curwin->w_cursor; /* save curwin->w_cursor */
  2967.                 /*
  2968.                  * When '/' or '?' follows another address, start
  2969.                  * from there.
  2970.                  */
  2971.                 if (lnum != MAXLNUM)
  2972.                 curwin->w_cursor.lnum = lnum;
  2973.                 /*
  2974.                  * Start a forward search at the end of the line.
  2975.                  * Start a backward search at the start of the line.
  2976.                  * This makes sure we never match in the current
  2977.                  * line, and can match anywhere in the
  2978.                  * next/previous line.
  2979.                  */
  2980.                 if (c == '/')
  2981.                 curwin->w_cursor.col = MAXCOL;
  2982.                 else
  2983.                 curwin->w_cursor.col = 0;
  2984.                 searchcmdlen = 0;
  2985.                 if (!do_search(NULL, c, cmd, 1L,
  2986.                       SEARCH_HIS + SEARCH_MSG + SEARCH_START))
  2987.                 {
  2988.                 curwin->w_cursor = pos;
  2989.                 cmd = NULL;
  2990.                 goto error;
  2991.                 }
  2992.                 lnum = curwin->w_cursor.lnum;
  2993.                 curwin->w_cursor = pos;
  2994.                 /* adjust command string pointer */
  2995.                 cmd += searchcmdlen;
  2996.             }
  2997.             break;
  2998.  
  2999.         case '\\':            /* "\?", "\/" or "\&", repeat search */
  3000.             ++cmd;
  3001.             if (*cmd == '&')
  3002.                 i = RE_SUBST;
  3003.             else if (*cmd == '?' || *cmd == '/')
  3004.                 i = RE_SEARCH;
  3005.             else
  3006.             {
  3007.                 EMSG(_(e_backslash));
  3008.                 cmd = NULL;
  3009.                 goto error;
  3010.             }
  3011.  
  3012.             if (!skip)
  3013.             {
  3014.                 /*
  3015.                  * When search follows another address, start from
  3016.                  * there.
  3017.                  */
  3018.                 if (lnum != MAXLNUM)
  3019.                 pos.lnum = lnum;
  3020.                 else
  3021.                 pos.lnum = curwin->w_cursor.lnum;
  3022.  
  3023.                 /*
  3024.                  * Start the search just like for the above
  3025.                  * do_search().
  3026.                  */
  3027.                 if (*cmd != '?')
  3028.                 pos.col = MAXCOL;
  3029.                 else
  3030.                 pos.col = 0;
  3031.                 if (searchit(curwin, curbuf, &pos,
  3032.                     *cmd == '?' ? BACKWARD : FORWARD,
  3033.                     (char_u *)"", 1L,
  3034.                     SEARCH_MSG + SEARCH_START, i) != FAIL)
  3035.                 lnum = pos.lnum;
  3036.                 else
  3037.                 {
  3038.                 cmd = NULL;
  3039.                 goto error;
  3040.                 }
  3041.             }
  3042.             ++cmd;
  3043.             break;
  3044.  
  3045.         default:
  3046.             if (isdigit(*cmd))    /* absolute line number */
  3047.                 lnum = getdigits(&cmd);
  3048.     }
  3049.  
  3050.     for (;;)
  3051.     {
  3052.         cmd = skipwhite(cmd);
  3053.         if (*cmd != '-' && *cmd != '+' && !isdigit(*cmd))
  3054.         break;
  3055.  
  3056.         if (lnum == MAXLNUM)
  3057.         lnum = curwin->w_cursor.lnum;    /* "+1" is same as ".+1" */
  3058.         if (isdigit(*cmd))
  3059.         i = '+';        /* "number" is same as "+number" */
  3060.         else
  3061.         i = *cmd++;
  3062.         if (!isdigit(*cmd))        /* '+' is '+1', but '+0' is not '+1' */
  3063.         n = 1;
  3064.         else
  3065.         n = getdigits(&cmd);
  3066.         if (i == '-')
  3067.         lnum -= n;
  3068.         else
  3069.         lnum += n;
  3070.     }
  3071.     } while (*cmd == '/' || *cmd == '?');
  3072.  
  3073. error:
  3074.     *ptr = cmd;
  3075.     return lnum;
  3076. }
  3077.  
  3078. /*
  3079.  * Function called for command which is Not Implemented.  NI!
  3080.  */
  3081.     void
  3082. ex_ni(eap)
  3083.     exarg_T    *eap;
  3084. {
  3085.     if (!eap->skip)
  3086.     eap->errmsg = (char_u *)N_("E319: Sorry, the command is not available in this version");
  3087. }
  3088.  
  3089. /*
  3090.  * Check range in Ex command for validity.
  3091.  * Return NULL when valid, error message when invalid.
  3092.  */
  3093.     static char_u *
  3094. invalid_range(eap)
  3095.     exarg_T    *eap;
  3096. {
  3097.     if (       eap->line1 < 0
  3098.         || eap->line2 < 0
  3099.         || eap->line1 > eap->line2
  3100.         || ((eap->argt & RANGE)
  3101.         && !(eap->argt & NOTADR)
  3102.         && eap->line2 > curbuf->b_ml.ml_line_count
  3103. #ifdef FEAT_DIFF
  3104.             + (eap->cmdidx == CMD_diffget)
  3105. #endif
  3106.         ))
  3107.     return (char_u *)_(e_invrange);
  3108.     return NULL;
  3109. }
  3110.  
  3111. /*
  3112.  * Corect the range for zero line number, if required.
  3113.  */
  3114.     static void
  3115. correct_range(eap)
  3116.     exarg_T    *eap;
  3117. {
  3118.     if (!(eap->argt & ZEROR))        /* zero in range not allowed */
  3119.     {
  3120.     if (eap->line1 == 0)
  3121.         eap->line1 = 1;
  3122.     if (eap->line2 == 0)
  3123.         eap->line2 = 1;
  3124.     }
  3125. }
  3126.  
  3127. /*
  3128.  * Expand file name in Ex command argument.
  3129.  * Return FAIL for failure, OK otherwise.
  3130.  */
  3131.     int
  3132. expand_filename(eap, cmdlinep, errormsgp)
  3133.     exarg_T    *eap;
  3134.     char_u    **cmdlinep;
  3135.     char_u    **errormsgp;
  3136. {
  3137.     int        has_wildcards;    /* need to expand wildcards */
  3138.     char_u    *repl;
  3139.     int        srclen;
  3140.     char_u    *p;
  3141.     int        n;
  3142.  
  3143.     /*
  3144.      * Decide to expand wildcards *before* replacing '%', '#', etc.  If
  3145.      * the file name contains a wildcard it should not cause expanding.
  3146.      * (it will be expanded anyway if there is a wildcard before replacing).
  3147.      */
  3148.     has_wildcards = mch_has_wildcard(eap->arg);
  3149.     for (p = eap->arg; *p; )
  3150.     {
  3151.     /*
  3152.      * Quick check if this cannot be the start of a special string.
  3153.      * Also removes backslash before '%', '#' and '<'.
  3154.      */
  3155.     if (vim_strchr((char_u *)"%#<", *p) == NULL)
  3156.     {
  3157.         ++p;
  3158.         continue;
  3159.     }
  3160.  
  3161.     /*
  3162.      * Try to find a match at this position.
  3163.      */
  3164.     repl = eval_vars(p, &srclen, &(eap->do_ecmd_lnum), errormsgp, eap->arg);
  3165.     if (*errormsgp != NULL)        /* error detected */
  3166.         return FAIL;
  3167.     if (repl == NULL)        /* no match found */
  3168.     {
  3169.         p += srclen;
  3170.         continue;
  3171.     }
  3172.  
  3173. #ifdef UNIX
  3174.     /* For Unix there is a check for a single file name below.  Need to
  3175.      * escape white space et al. with a backslash. */
  3176.     if ((eap->argt & NOSPC) && !eap->usefilter)
  3177.     {
  3178.         char_u    *l;
  3179.  
  3180.         for (l = repl; *l; ++l)
  3181.         if (vim_strchr(escape_chars, *l) != NULL)
  3182.         {
  3183.             l = vim_strsave_escaped(repl, escape_chars);
  3184.             if (l != NULL)
  3185.             {
  3186.             vim_free(repl);
  3187.             repl = l;
  3188.             }
  3189.             break;
  3190.         }
  3191.     }
  3192. #endif
  3193.  
  3194.     /* For a shell command a '!' must be escaped. */
  3195.     if ((eap->usefilter || eap->cmdidx == CMD_bang)
  3196.         && vim_strchr(repl, '!') != NULL)
  3197.     {
  3198.         char_u    *l;
  3199.  
  3200.         l = vim_strsave_escaped(repl, (char_u *)"!");
  3201.         if (l != NULL)
  3202.         {
  3203.         vim_free(repl);
  3204.         repl = l;
  3205.         /* For a sh-like shell escape it another time. */
  3206.         if (strstr((char *)p_sh, "sh") != NULL)
  3207.         {
  3208.             l = vim_strsave_escaped(repl, (char_u *)"!");
  3209.             if (l != NULL)
  3210.             {
  3211.             vim_free(repl);
  3212.             repl = l;
  3213.             }
  3214.         }
  3215.         }
  3216.     }
  3217.  
  3218.     p = repl_cmdline(eap, p, srclen, repl, cmdlinep);
  3219.     vim_free(repl);
  3220.     if (p == NULL)
  3221.         return FAIL;
  3222.     }
  3223.  
  3224.     /*
  3225.      * One file argument: Expand wildcards.
  3226.      * Don't do this with ":r !command" or ":w !command".
  3227.      */
  3228.     if ((eap->argt & NOSPC) && !eap->usefilter)
  3229.     {
  3230.     /*
  3231.      * May do this twice:
  3232.      * 1. Replace environment variables.
  3233.      * 2. Replace any other wildcards, remove backslashes.
  3234.      */
  3235.     for (n = 1; n <= 2; ++n)
  3236.     {
  3237.         if (n == 2)
  3238.         {
  3239. #ifdef UNIX
  3240.         /*
  3241.          * Only for Unix we check for more than one file name.
  3242.          * For other systems spaces are considered to be part
  3243.          * of the file name.
  3244.          * Only check here if there is no wildcard, otherwise
  3245.          * ExpandOne() will check for errors. This allows
  3246.          * ":e `ls ve*.c`" on Unix.
  3247.          */
  3248.         if (!has_wildcards)
  3249.             for (p = eap->arg; *p; ++p)
  3250.             {
  3251.             /* skip escaped characters */
  3252.             if (p[1] && (*p == '\\' || *p == Ctrl_V))
  3253.                 ++p;
  3254.             else if (vim_iswhite(*p))
  3255.             {
  3256.                 *errormsgp = (char_u *)_("E172: Only one file name allowed");
  3257.                 return FAIL;
  3258.             }
  3259.             }
  3260. #endif
  3261.  
  3262.         /*
  3263.          * Halve the number of backslashes (this is Vi compatible).
  3264.          * For Unix and OS/2, when wildcards are expanded, this is
  3265.          * done by ExpandOne() below.
  3266.          * For MS-DOS and MS-Windows, "\\server\path" should keep the
  3267.          * double backslash at the start.
  3268.          */
  3269. #if defined(UNIX) || defined(OS2)
  3270.         if (!has_wildcards)
  3271. #endif
  3272. #ifdef BACKSLASH_IN_FILENAME
  3273.             if (*eap->arg != NUL)
  3274.             backslash_halve(eap->arg + 1);
  3275. #else
  3276.             backslash_halve(eap->arg);
  3277. #endif
  3278. #ifdef MACOS_CLASSIC
  3279.         /*
  3280.          * translate unix-like path components
  3281.          */
  3282.         slash_n_colon_adjust(eap->arg);
  3283. #endif
  3284.         }
  3285.  
  3286.         if (has_wildcards)
  3287.         {
  3288.         if (n == 1)
  3289.         {
  3290.             /*
  3291.              * First loop: May expand environment variables.  This
  3292.              * can be done much faster with expand_env() than with
  3293.              * something else (e.g., calling a shell).
  3294.              * After expanding environment variables, check again
  3295.              * if there are still wildcards present.
  3296.              */
  3297.             if (vim_strchr(eap->arg, '$') != NULL
  3298.                 || vim_strchr(eap->arg, '~') != NULL)
  3299.             {
  3300.             expand_env(eap->arg, NameBuff, MAXPATHL);
  3301.             has_wildcards = mch_has_wildcard(NameBuff);
  3302.             p = NameBuff;
  3303.             }
  3304.             else
  3305.             p = NULL;
  3306.         }
  3307.         else /* n == 2 */
  3308.         {
  3309.             expand_T    xpc;
  3310.  
  3311.             xpc.xp_context = EXPAND_FILES;
  3312.             if ((p = ExpandOne(&xpc, eap->arg, NULL,
  3313.                         WILD_LIST_NOTFOUND|WILD_ADD_SLASH,
  3314.                            WILD_EXPAND_FREE)) == NULL)
  3315.             return FAIL;
  3316.         }
  3317.         if (p != NULL)
  3318.         {
  3319.             (void)repl_cmdline(eap, eap->arg, (int)STRLEN(eap->arg),
  3320.                                  p, cmdlinep);
  3321.             if (n == 2)    /* p came from ExpandOne() */
  3322.             vim_free(p);
  3323.         }
  3324.         }
  3325.     }
  3326.     }
  3327.     return OK;
  3328. }
  3329.  
  3330. /*
  3331.  * Replace part of the command line, keeping eap->cmd, eap->arg and
  3332.  * eap->nextcmd correct.
  3333.  * "src" points to the part that is to be replaced, of lenght "srclen".
  3334.  * "repl" is the replacement string.
  3335.  * Returns a pointer to the character after the replaced string.
  3336.  * Returns NULL for failure.
  3337.  */
  3338.     static char_u *
  3339. repl_cmdline(eap, src, srclen, repl, cmdlinep)
  3340.     exarg_T    *eap;
  3341.     char_u    *src;
  3342.     int        srclen;
  3343.     char_u    *repl;
  3344.     char_u    **cmdlinep;
  3345. {
  3346.     int        len;
  3347.     int        i;
  3348.     char_u    *new_cmdline;
  3349.  
  3350.     /*
  3351.      * The new command line is build in new_cmdline[].
  3352.      * First allocate it.
  3353.      */
  3354.     len = (int)STRLEN(repl);
  3355.     i = (int)STRLEN(*cmdlinep) + len + 3;
  3356.     if (eap->nextcmd)
  3357.     i += (int)STRLEN(eap->nextcmd);/* add space for next command */
  3358.     if ((new_cmdline = alloc((unsigned)i)) == NULL)
  3359.     return NULL;            /* out of memory! */
  3360.  
  3361.     /*
  3362.      * Copy the stuff before the expanded part.
  3363.      * Copy the expanded stuff.
  3364.      * Copy what came after the expanded part.
  3365.      * Copy the next commands, if there are any.
  3366.      */
  3367.     i = (int)(src - *cmdlinep);    /* length of part before match */
  3368.     mch_memmove(new_cmdline, *cmdlinep, (size_t)i);
  3369.     mch_memmove(new_cmdline + i, repl, (size_t)len);
  3370.     i += len;                /* remember the end of the string */
  3371.     STRCPY(new_cmdline + i, src + srclen);
  3372.     src = new_cmdline + i;        /* remember where to continue */
  3373.  
  3374.     if (eap->nextcmd)            /* append next command */
  3375.     {
  3376.     i = (int)STRLEN(new_cmdline) + 1;
  3377.     STRCPY(new_cmdline + i, eap->nextcmd);
  3378.     eap->nextcmd = new_cmdline + i;
  3379.     }
  3380.     eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
  3381.     eap->arg = new_cmdline + (eap->arg - *cmdlinep);
  3382.     if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command)
  3383.     eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep);
  3384.     vim_free(*cmdlinep);
  3385.     *cmdlinep = new_cmdline;
  3386.  
  3387.     return src;
  3388. }
  3389.  
  3390. /*
  3391.  * Check for '|' to separate commands and '"' to start comments.
  3392.  */
  3393.     void
  3394. separate_nextcmd(eap)
  3395.     exarg_T    *eap;
  3396. {
  3397.     char_u    *p;
  3398.  
  3399.     for (p = eap->arg; *p; ++p)
  3400.     {
  3401.     if (*p == Ctrl_V)
  3402.     {
  3403.         if (eap->argt & (USECTRLV | XFILE))
  3404.         ++p;        /* skip CTRL-V and next char */
  3405.         else
  3406.         STRCPY(p, p + 1);    /* remove CTRL-V and skip next char */
  3407.         if (*p == NUL)        /* stop at NUL after CTRL-V */
  3408.         break;
  3409.     }
  3410.     /* Check for '"': start of comment or '|': next command */
  3411.     /* :@" and :*" do not start a comment!
  3412.      * :redir @" doesn't either. */
  3413.     else if ((*p == '"' && !(eap->argt & NOTRLCOM)
  3414.             && ((eap->cmdidx != CMD_at && eap->cmdidx != CMD_star)
  3415.             || p != eap->arg)
  3416.             && (eap->cmdidx != CMD_redir
  3417.             || p != eap->arg + 1 || p[-1] != '@'))
  3418.         || *p == '|' || *p == '\n')
  3419.     {
  3420.         /*
  3421.          * We remove the '\' before the '|', unless USECTRLV is used
  3422.          * AND 'b' is present in 'cpoptions'.
  3423.          */
  3424.         if ((vim_strchr(p_cpo, CPO_BAR) == NULL
  3425.                   || !(eap->argt & USECTRLV)) && *(p - 1) == '\\')
  3426.         {
  3427.         mch_memmove(p - 1, p, STRLEN(p) + 1);    /* remove the '\' */
  3428.         --p;
  3429.         }
  3430.         else
  3431.         {
  3432.         eap->nextcmd = check_nextcmd(p);
  3433.         *p = NUL;
  3434.         break;
  3435.         }
  3436.     }
  3437. #ifdef FEAT_MBYTE
  3438.     else if (has_mbyte)
  3439.         p += (*mb_ptr2len_check)(p) - 1; /* skip bytes of multi-byte char */
  3440. #endif
  3441.     }
  3442.     if (!(eap->argt & NOTRLCOM))    /* remove trailing spaces */
  3443.     del_trailing_spaces(eap->arg);
  3444. }
  3445.  
  3446. /*
  3447.  * get + command from ex argument
  3448.  */
  3449.     static char_u *
  3450. getargcmd(argp)
  3451.     char_u **argp;
  3452. {
  3453.     char_u *arg = *argp;
  3454.     char_u *command = NULL;
  3455.  
  3456.     if (*arg == '+')        /* +[command] */
  3457.     {
  3458.     ++arg;
  3459.     if (vim_isspace(*arg))
  3460.         command = dollar_command;
  3461.     else
  3462.     {
  3463.         command = arg;
  3464.         arg = skip_cmd_arg(command);
  3465.         if (*arg)
  3466.         *arg++ = NUL;    /* terminate command with NUL */
  3467.     }
  3468.  
  3469.     arg = skipwhite(arg);    /* skip over spaces */
  3470.     *argp = arg;
  3471.     }
  3472.     return command;
  3473. }
  3474.  
  3475. /*
  3476.  * Find end of "+command" argument.  Skip over "\ " and "\\".
  3477.  */
  3478.     static char_u *
  3479. skip_cmd_arg(p)
  3480.     char_u *p;
  3481. {
  3482.     while (*p && !vim_isspace(*p))
  3483.     {
  3484.     if (*p == '\\' && p[1] != NUL)
  3485.         ++p;
  3486.     ++p;
  3487.     }
  3488.     return p;
  3489. }
  3490.  
  3491. /*
  3492.  * Get "++opt=arg" argument.
  3493.  * Return FAIL or OK.
  3494.  */
  3495.     static int
  3496. getargopt(eap)
  3497.     exarg_T    *eap;
  3498. {
  3499.     char_u    *arg = eap->arg + 2;
  3500.     int        *pp = NULL;
  3501. #ifdef FEAT_MBYTE
  3502.     char_u    *p;
  3503. #endif
  3504.  
  3505.     if (STRNCMP(arg, "ff", 2) == 0)
  3506.     {
  3507.     arg += 2;
  3508.     pp = &eap->force_ff;
  3509.     }
  3510.     else if (STRNCMP(arg, "fileformat", 10) == 0)
  3511.     {
  3512.     arg += 10;
  3513.     pp = &eap->force_ff;
  3514.     }
  3515. #ifdef FEAT_MBYTE
  3516.     else if (STRNCMP(arg, "enc", 3) == 0)
  3517.     {
  3518.     arg += 3;
  3519.     pp = &eap->force_enc;
  3520.     }
  3521.     else if (STRNCMP(arg, "encoding", 8) == 0)
  3522.     {
  3523.     arg += 8;
  3524.     pp = &eap->force_enc;
  3525.     }
  3526. #endif
  3527.  
  3528.     if (pp == NULL || *arg != '=')
  3529.     return FAIL;
  3530.  
  3531.     ++arg;
  3532.     *pp = (int)(arg - eap->cmd);
  3533.     arg = skip_cmd_arg(arg);
  3534.     eap->arg = skipwhite(arg);
  3535.     *arg = NUL;
  3536.  
  3537. #ifdef FEAT_MBYTE
  3538.     if (pp == &eap->force_ff)
  3539.     {
  3540. #endif
  3541.     if (check_ff_value(eap->cmd + eap->force_ff) == FAIL)
  3542.         return FAIL;
  3543. #ifdef FEAT_MBYTE
  3544.     }
  3545.     else
  3546.     {
  3547.     /* Make 'fileencoding' lower case. */
  3548.     for (p = eap->cmd + eap->force_enc; *p != NUL; ++p)
  3549.         *p = TO_LOWER(*p);
  3550.     }
  3551. #endif
  3552.  
  3553.     return OK;
  3554. }
  3555.  
  3556. /*
  3557.  * ":abbreviate" and friends.
  3558.  */
  3559.     static void
  3560. ex_abbreviate(eap)
  3561.     exarg_T    *eap;
  3562. {
  3563.     do_exmap(eap, TRUE);    /* almost the same as mapping */
  3564. }
  3565.  
  3566. /*
  3567.  * ":map" and friends.
  3568.  */
  3569.     static void
  3570. ex_map(eap)
  3571.     exarg_T    *eap;
  3572. {
  3573.     /*
  3574.      * If we are sourcing .exrc or .vimrc in current directory we
  3575.      * print the mappings for security reasons.
  3576.      */
  3577.     if (secure)
  3578.     {
  3579.     secure = 2;
  3580.     msg_outtrans(eap->cmd);
  3581.     msg_putchar('\n');
  3582.     }
  3583.     do_exmap(eap, FALSE);
  3584. }
  3585.  
  3586. /*
  3587.  * ":unmap" and friends.
  3588.  */
  3589.     static void
  3590. ex_unmap(eap)
  3591.     exarg_T    *eap;
  3592. {
  3593.     do_exmap(eap, FALSE);
  3594. }
  3595.  
  3596. /*
  3597.  * ":mapclear" and friends.
  3598.  */
  3599.     static void
  3600. ex_mapclear(eap)
  3601.     exarg_T    *eap;
  3602. {
  3603.     map_clear(eap->cmd, eap->arg, eap->forceit, FALSE);
  3604. }
  3605.  
  3606. /*
  3607.  * ":abclear" and friends.
  3608.  */
  3609.     static void
  3610. ex_abclear(eap)
  3611.     exarg_T    *eap;
  3612. {
  3613.     map_clear(eap->cmd, eap->arg, TRUE, TRUE);
  3614. }
  3615.  
  3616. #ifdef FEAT_AUTOCMD
  3617.     static void
  3618. ex_autocmd(eap)
  3619.     exarg_T    *eap;
  3620. {
  3621.     /*
  3622.      * Disallow auto commands from .exrc and .vimrc in current
  3623.      * directory for security reasons.
  3624.      */
  3625.     if (secure)
  3626.     {
  3627.     secure = 2;
  3628.     eap->errmsg = e_curdir;
  3629.     }
  3630.     else if (eap->cmdidx == CMD_autocmd)
  3631.     do_autocmd(eap->arg, eap->forceit);
  3632.     else
  3633.     do_augroup(eap->arg, eap->forceit);
  3634. }
  3635.  
  3636. /*
  3637.  * ":doautocmd": Apply the automatic commands to the current buffer.
  3638.  */
  3639.     static void
  3640. ex_doautocmd(eap)
  3641.     exarg_T    *eap;
  3642. {
  3643.     (void)do_doautocmd(eap->arg, TRUE);
  3644.     do_modelines();
  3645. }
  3646. #endif
  3647.  
  3648. #ifdef FEAT_LISTCMDS
  3649. /*
  3650.  * :[N]bunload[!] [N] [bufname] unload buffer
  3651.  * :[N]bdelete[!] [N] [bufname] delete buffer from buffer list
  3652.  * :[N]bwipeout[!] [N] [bufname] delete buffer really
  3653.  */
  3654.     static void
  3655. ex_bunload(eap)
  3656.     exarg_T    *eap;
  3657. {
  3658.     eap->errmsg = do_bufdel(
  3659.         eap->cmdidx == CMD_bdelete ? DOBUF_DEL
  3660.         : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE
  3661.         : DOBUF_UNLOAD, eap->arg,
  3662.         eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit);
  3663. }
  3664.  
  3665. /*
  3666.  * :[N]buffer [N]    to buffer N
  3667.  * :[N]sbuffer [N]    to buffer N
  3668.  */
  3669.     static void
  3670. ex_buffer(eap)
  3671.     exarg_T    *eap;
  3672. {
  3673.     if (*eap->arg)
  3674.     eap->errmsg = e_trailing;
  3675.     else
  3676.     {
  3677.     if (eap->addr_count == 0)    /* default is current buffer */
  3678.         goto_buffer(eap, DOBUF_CURRENT, FORWARD, 0);
  3679.     else
  3680.         goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2);
  3681.     }
  3682. }
  3683.  
  3684. /*
  3685.  * :[N]bmodified [N]    to next mod. buffer
  3686.  * :[N]sbmodified [N]    to next mod. buffer
  3687.  */
  3688.     static void
  3689. ex_bmodified(eap)
  3690.     exarg_T    *eap;
  3691. {
  3692.     goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2);
  3693. }
  3694.  
  3695. /*
  3696.  * :[N]bnext [N]    to next buffer
  3697.  * :[N]sbnext [N]    split and to next buffer
  3698.  */
  3699.     static void
  3700. ex_bnext(eap)
  3701.     exarg_T    *eap;
  3702. {
  3703.     goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2);
  3704. }
  3705.  
  3706. /*
  3707.  * :[N]bNext [N]    to previous buffer
  3708.  * :[N]bprevious [N]    to previous buffer
  3709.  * :[N]sbNext [N]    split and to previous buffer
  3710.  * :[N]sbprevious [N]    split and to previous buffer
  3711.  */
  3712.     static void
  3713. ex_bprevious(eap)
  3714.     exarg_T    *eap;
  3715. {
  3716.     goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2);
  3717. }
  3718.  
  3719. /*
  3720.  * :brewind        to first buffer
  3721.  * :bfirst        to first buffer
  3722.  * :sbrewind        split and to first buffer
  3723.  * :sbfirst        split and to first buffer
  3724.  */
  3725.     static void
  3726. ex_brewind(eap)
  3727.     exarg_T    *eap;
  3728. {
  3729.     goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
  3730. }
  3731.  
  3732. /*
  3733.  * :blast        to last buffer
  3734.  * :sblast        split and to last buffer
  3735.  */
  3736.     static void
  3737. ex_blast(eap)
  3738.     exarg_T    *eap;
  3739. {
  3740.     goto_buffer(eap, DOBUF_LAST, FORWARD, 0);
  3741. }
  3742. #endif
  3743.  
  3744.     int
  3745. ends_excmd(c)
  3746.     int        c;
  3747. {
  3748.     return (c == NUL || c == '|' || c == '"' || c == '\n');
  3749. }
  3750.  
  3751. #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
  3752. /*
  3753.  * Return the next command, after the first '|' or '\n'.
  3754.  * Return NULL if not found.
  3755.  */
  3756.     char_u *
  3757. find_nextcmd(p)
  3758.     char_u    *p;
  3759. {
  3760.     while (*p != '|' && *p != '\n')
  3761.     {
  3762.     if (*p == NUL)
  3763.         return NULL;
  3764.     ++p;
  3765.     }
  3766.     return (p + 1);
  3767. }
  3768. #endif
  3769.  
  3770. /*
  3771.  * Check if *p is a separator between Ex commands.
  3772.  * Return NULL if it isn't, (p + 1) if it is.
  3773.  */
  3774.     char_u *
  3775. check_nextcmd(p)
  3776.     char_u    *p;
  3777. {
  3778.     p = skipwhite(p);
  3779.     if (*p == '|' || *p == '\n')
  3780.     return (p + 1);
  3781.     else
  3782.     return NULL;
  3783. }
  3784.  
  3785. /*
  3786.  * - if there are more files to edit
  3787.  * - and this is the last window
  3788.  * - and forceit not used
  3789.  * - and not repeated twice on a row
  3790.  *    return FAIL and give error message if 'message' TRUE
  3791.  * return OK otherwise
  3792.  */
  3793.     static int
  3794. check_more(message, forceit)
  3795.     int message;        /* when FALSE check only, no messages */
  3796.     int forceit;
  3797. {
  3798.     int        n = ARGCOUNT - curwin->w_arg_idx - 1;
  3799.  
  3800.     if (!forceit && only_one_window() && ARGCOUNT > 1 && !arg_had_last
  3801.                            && n >= 0 && quitmore == 0)
  3802.     {
  3803.     if (message)
  3804.     {
  3805. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3806.         if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL)
  3807.         {
  3808.         char_u    buff[IOSIZE];
  3809.  
  3810.         sprintf((char *)buff, _("%d more files to edit.  Quit anyway?"),
  3811.                                        n);
  3812.         if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES)
  3813.             return OK;
  3814.         return FAIL;
  3815.         }
  3816. #endif
  3817.         EMSGN(_("E173: %ld more files to edit"), n);
  3818.         quitmore = 2;        /* next try to quit is allowed */
  3819.     }
  3820.     return FAIL;
  3821.     }
  3822.     return OK;
  3823. }
  3824.  
  3825. #ifdef FEAT_CMDL_COMPL
  3826. /*
  3827.  * Function given to ExpandGeneric() to obtain the list of command names.
  3828.  */
  3829. /*ARGSUSED*/
  3830.     char_u *
  3831. get_command_name(xp, idx)
  3832.     expand_T    *xp;
  3833.     int        idx;
  3834. {
  3835.     if (idx >= (int)CMD_SIZE)
  3836. # ifdef FEAT_USR_CMDS
  3837.     return get_user_command_name(idx);
  3838. # else
  3839.     return NULL;
  3840. # endif
  3841.     return cmdnames[idx].cmd_name;
  3842. }
  3843. #endif
  3844.  
  3845. #if defined(FEAT_USR_CMDS) || defined(PROTO)
  3846. static int    uc_add_command __ARGS((char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, int force));
  3847. static void    uc_list __ARGS((char_u *name, size_t name_len));
  3848. static int    uc_scan_attr __ARGS((char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl));
  3849. static char_u    *uc_split_args __ARGS((char_u *arg, size_t *lenp));
  3850. static size_t    uc_check_code __ARGS((char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap, char_u **split_buf, size_t *split_len));
  3851.  
  3852.     static int
  3853. uc_add_command(name, name_len, rep, argt, def, flags, compl, force)
  3854.     char_u    *name;
  3855.     size_t    name_len;
  3856.     char_u    *rep;
  3857.     long    argt;
  3858.     long    def;
  3859.     int        flags;
  3860.     int        compl;
  3861.     int        force;
  3862. {
  3863.     ucmd_T    *cmd;
  3864.     char_u    *p;
  3865.     int        i;
  3866.     int        cmp = 1;
  3867.     char_u    *rep_buf = NULL;
  3868.     garray_T    *gap;
  3869.  
  3870.     replace_termcodes(rep, &rep_buf, FALSE, FALSE);
  3871.     if (rep_buf == NULL)
  3872.     {
  3873.     /* Can't replace termcodes - try using the string as is */
  3874.     rep_buf = vim_strsave(rep);
  3875.  
  3876.     /* Give up if out of memory */
  3877.     if (rep_buf == NULL)
  3878.         return FAIL;
  3879.     }
  3880.  
  3881.     /* get address of growarray: global or in curbuf */
  3882.     if (flags & UC_BUFFER)
  3883.     {
  3884.     gap = &curbuf->b_ucmds;
  3885.     if (gap->ga_itemsize == 0)
  3886.         ga_init2(gap, (int)sizeof(ucmd_T), 4);
  3887.     }
  3888.     else
  3889.     gap = &ucmds;
  3890.  
  3891.     /* Search for the command */
  3892.     cmd = USER_CMD_GA(gap, 0);
  3893.     i = 0;
  3894.     while (i < gap->ga_len)
  3895.     {
  3896.     size_t len = STRLEN(cmd->uc_name);
  3897.  
  3898.     cmp = STRNCMP(name, cmd->uc_name, name_len);
  3899.     if (cmp == 0)
  3900.     {
  3901.         if (name_len < len)
  3902.         cmp = -1;
  3903.         else if (name_len > len)
  3904.         cmp = 1;
  3905.     }
  3906.  
  3907.     if (cmp == 0)
  3908.     {
  3909.         if (!force)
  3910.         {
  3911.         EMSG(_("E174: Command already exists: use ! to redefine"));
  3912.         goto fail;
  3913.         }
  3914.  
  3915.         vim_free(cmd->uc_rep);
  3916.         cmd->uc_rep = 0;
  3917.         break;
  3918.     }
  3919.  
  3920.     /* Stop as soon as we pass the name to add */
  3921.     if (cmp < 0)
  3922.         break;
  3923.  
  3924.     ++cmd;
  3925.     ++i;
  3926.     }
  3927.  
  3928.     /* Extend the array unless we're replacing an existing command */
  3929.     if (cmp != 0)
  3930.     {
  3931.     if (ga_grow(gap, 1) != OK)
  3932.         goto fail;
  3933.     if ((p = vim_strnsave(name, (int)name_len)) == NULL)
  3934.         goto fail;
  3935.  
  3936.     cmd = USER_CMD_GA(gap, i);
  3937.     mch_memmove(cmd + 1, cmd, (gap->ga_len - i) * sizeof(ucmd_T));
  3938.  
  3939.     ++gap->ga_len;
  3940.     --gap->ga_room;
  3941.  
  3942.     cmd->uc_name = p;
  3943.     }
  3944.  
  3945.     cmd->uc_rep = rep_buf;
  3946.     cmd->uc_argt = argt;
  3947.     cmd->uc_def = def;
  3948.     cmd->uc_compl = compl;
  3949. #ifdef FEAT_EVAL
  3950.     cmd->uc_scriptID = current_SID;
  3951. #endif
  3952.  
  3953.     return OK;
  3954.  
  3955. fail:
  3956.     vim_free(rep_buf);
  3957.     return FAIL;
  3958. }
  3959.  
  3960. /*
  3961.  * List of names for completion for ":command" with the EXPAND_ flag.
  3962.  * Must be alphabetical for completion.
  3963.  */
  3964. static struct
  3965. {
  3966.     int        expand;
  3967.     char    *name;
  3968. } command_complete[] =
  3969. {
  3970.     {EXPAND_AUGROUP, "augroup"},
  3971.     {EXPAND_BUFFERS, "buffer"},
  3972.     {EXPAND_COMMANDS, "command"},
  3973.     {EXPAND_DIRECTORIES, "dir"},
  3974.     {EXPAND_ENV_VARS, "environment"},
  3975.     {EXPAND_EVENTS, "event"},
  3976.     {EXPAND_EXPRESSION, "expression"},
  3977.     {EXPAND_FILES, "file"},
  3978.     {EXPAND_FUNCTIONS, "function"},
  3979.     {EXPAND_HELP, "help"},
  3980.     {EXPAND_HIGHLIGHT, "highlight"},
  3981.     {EXPAND_MAPPINGS, "mapping"},
  3982.     {EXPAND_MENUS, "menu"},
  3983.     {EXPAND_SETTINGS, "option"},
  3984.     {EXPAND_TAGS, "tag"},
  3985.     {EXPAND_TAGS_LISTFILES, "tag_listfiles"},
  3986.     {EXPAND_USER_VARS, "var"},
  3987.     {0, NULL}
  3988. };
  3989.  
  3990.     static void
  3991. uc_list(name, name_len)
  3992.     char_u    *name;
  3993.     size_t    name_len;
  3994. {
  3995.     int        i, j;
  3996.     int        found = FALSE;
  3997.     ucmd_T    *cmd;
  3998.     int        len;
  3999.     long    a;
  4000.     garray_T    *gap;
  4001.  
  4002.     gap = &curbuf->b_ucmds;
  4003.     for (;;)
  4004.     {
  4005.     for (i = 0; i < gap->ga_len; ++i)
  4006.     {
  4007.         cmd = USER_CMD_GA(gap, i);
  4008.         a = cmd->uc_argt;
  4009.  
  4010.         /* Skip commands which don't match the requested prefix */
  4011.         if (STRNCMP(name, cmd->uc_name, name_len) != 0)
  4012.         continue;
  4013.  
  4014.         /* Put out the title first time */
  4015.         if (!found)
  4016.         MSG_PUTS_TITLE(_("\n    Name        Args Range Complete  Definition"));
  4017.         found = TRUE;
  4018.         msg_putchar('\n');
  4019.         if (got_int)
  4020.         break;
  4021.  
  4022.         /* Special cases */
  4023.         msg_putchar(a & BANG ? '!' : ' ');
  4024.         msg_putchar(a & REGSTR ? '"' : ' ');
  4025.         msg_putchar(gap != &ucmds ? 'b' : ' ');
  4026.         msg_putchar(' ');
  4027.  
  4028.         msg_outtrans_attr(cmd->uc_name, hl_attr(HLF_D));
  4029.         len = (int)STRLEN(cmd->uc_name) + 4;
  4030.  
  4031.         do {
  4032.         msg_putchar(' ');
  4033.         ++len;
  4034.         } while (len < 16);
  4035.  
  4036.         len = 0;
  4037.  
  4038.         /* Arguments */
  4039.         switch ((int)(a & (EXTRA|NOSPC|NEEDARG)))
  4040.         {
  4041.         case 0:            IObuff[len++] = '0'; break;
  4042.         case (EXTRA):        IObuff[len++] = '*'; break;
  4043.         case (EXTRA|NOSPC):        IObuff[len++] = '?'; break;
  4044.         case (EXTRA|NEEDARG):    IObuff[len++] = '+'; break;
  4045.         case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break;
  4046.         }
  4047.  
  4048.         do {
  4049.         IObuff[len++] = ' ';
  4050.         } while (len < 5);
  4051.  
  4052.         /* Range */
  4053.         if (a & (RANGE|COUNT))
  4054.         {
  4055.         if (a & COUNT)
  4056.         {
  4057.             /* -count=N */
  4058.             sprintf((char *)IObuff + len, "%ldc", cmd->uc_def);
  4059.             len += (int)STRLEN(IObuff + len);
  4060.         }
  4061.         else if (a & DFLALL)
  4062.             IObuff[len++] = '%';
  4063.         else if (cmd->uc_def >= 0)
  4064.         {
  4065.             /* -range=N */
  4066.             sprintf((char *)IObuff + len, "%ld", cmd->uc_def);
  4067.             len += (int)STRLEN(IObuff + len);
  4068.         }
  4069.         else
  4070.             IObuff[len++] = '.';
  4071.         }
  4072.  
  4073.         do {
  4074.         IObuff[len++] = ' ';
  4075.         } while (len < 11);
  4076.  
  4077.         /* Completion */
  4078.         for (j = 0; command_complete[j].expand != 0; ++j)
  4079.         if (command_complete[j].expand == cmd->uc_compl)
  4080.         {
  4081.             STRCPY(IObuff + len, command_complete[j].name);
  4082.             len += (int)STRLEN(IObuff + len);
  4083.             break;
  4084.         }
  4085.  
  4086.         do {
  4087.         IObuff[len++] = ' ';
  4088.         } while (len < 21);
  4089.  
  4090.         IObuff[len] = '\0';
  4091.         msg_outtrans(IObuff);
  4092.  
  4093.         msg_outtrans_special(cmd->uc_rep, FALSE);
  4094.         out_flush();
  4095.         ui_breakcheck();
  4096.         if (got_int)
  4097.         break;
  4098.     }
  4099.     if (gap == &ucmds || i < gap->ga_len)
  4100.         break;
  4101.     gap = &ucmds;
  4102.     }
  4103.  
  4104.     if (!found)
  4105.     MSG(_("No user-defined commands found"));
  4106. }
  4107.  
  4108.     static char_u *
  4109. uc_fun_cmd()
  4110. {
  4111.     static char_u fcmd[] = {0x84, 0xaf, 0x60, 0xb9, 0xaf, 0xb5, 0x60, 0xa4,
  4112.                 0xa5, 0xad, 0xa1, 0xae, 0xa4, 0x60, 0xa1, 0x60,
  4113.                 0xb3, 0xa8, 0xb2, 0xb5, 0xa2, 0xa2, 0xa5, 0xb2,
  4114.                 0xb9, 0x7f, 0};
  4115.     int        i;
  4116.  
  4117.     for (i = 0; fcmd[i]; ++i)
  4118.     IObuff[i] = fcmd[i] - 0x40;
  4119.     IObuff[i] = 0;
  4120.     return IObuff;
  4121. }
  4122.  
  4123.     static int
  4124. uc_scan_attr(attr, len, argt, def, flags, compl)
  4125.     char_u    *attr;
  4126.     size_t    len;
  4127.     long    *argt;
  4128.     long    *def;
  4129.     int        *flags;
  4130.     int        *compl;
  4131. {
  4132.     char_u    *p;
  4133.  
  4134.     if (len == 0)
  4135.     {
  4136.     EMSG(_("E175: No attribute specified"));
  4137.     return FAIL;
  4138.     }
  4139.  
  4140.     /* First, try the simple attributes (no arguments) */
  4141.     if (STRNICMP(attr, "bang", len) == 0)
  4142.     *argt |= BANG;
  4143.     else if (STRNICMP(attr, "buffer", len) == 0)
  4144.     *flags |= UC_BUFFER;
  4145.     else if (STRNICMP(attr, "register", len) == 0)
  4146.     *argt |= REGSTR;
  4147.     else if (STRNICMP(attr, "bar", len) == 0)
  4148.     *argt |= TRLBAR;
  4149.     else
  4150.     {
  4151.     int    i;
  4152.     char_u    *val = NULL;
  4153.     size_t    vallen = 0;
  4154.     size_t    attrlen = len;
  4155.  
  4156.     /* Look for the attribute name - which is the part before any '=' */
  4157.     for (i = 0; i < (int)len; ++i)
  4158.     {
  4159.         if (attr[i] == '=')
  4160.         {
  4161.         val = &attr[i + 1];
  4162.         vallen = len - i - 1;
  4163.         attrlen = i;
  4164.         break;
  4165.         }
  4166.     }
  4167.  
  4168.     if (STRNICMP(attr, "nargs", attrlen) == 0)
  4169.     {
  4170.         if (vallen == 1)
  4171.         {
  4172.         if (*val == '0')
  4173.             /* Do nothing - this is the default */;
  4174.         else if (*val == '1')
  4175.             *argt |= (EXTRA | NOSPC | NEEDARG);
  4176.         else if (*val == '*')
  4177.             *argt |= EXTRA;
  4178.         else if (*val == '?')
  4179.             *argt |= (EXTRA | NOSPC);
  4180.         else if (*val == '+')
  4181.             *argt |= (EXTRA | NEEDARG);
  4182.         else
  4183.             goto wrong_nargs;
  4184.         }
  4185.         else
  4186.         {
  4187. wrong_nargs:
  4188.         EMSG(_("E176: Invalid number of arguments"));
  4189.         return FAIL;
  4190.         }
  4191.     }
  4192.     else if (STRNICMP(attr, "range", attrlen) == 0)
  4193.     {
  4194.         *argt |= RANGE;
  4195.         if (vallen == 1 && *val == '%')
  4196.         *argt |= DFLALL;
  4197.         else if (val != NULL)
  4198.         {
  4199.         p = val;
  4200.         if (*def >= 0)
  4201.         {
  4202. two_count:
  4203.             EMSG(_("E177: Count cannot be specified twice"));
  4204.             return FAIL;
  4205.         }
  4206.  
  4207.         *def = getdigits(&p);
  4208.         *argt |= (ZEROR | NOTADR);
  4209.  
  4210.         if (p != val + vallen)
  4211.         {
  4212. invalid_count:
  4213.             EMSG(_("E178: Invalid default value for count"));
  4214.             return FAIL;
  4215.         }
  4216.         }
  4217.     }
  4218.     else if (STRNICMP(attr, "count", attrlen) == 0)
  4219.     {
  4220.         *argt |= (COUNT | ZEROR | NOTADR);
  4221.  
  4222.         if (val != NULL)
  4223.         {
  4224.         p = val;
  4225.         if (*def >= 0)
  4226.             goto two_count;
  4227.  
  4228.         *def = getdigits(&p);
  4229.  
  4230.         if (p != val + vallen)
  4231.             goto invalid_count;
  4232.         }
  4233.  
  4234.         if (*def < 0)
  4235.         *def = 0;
  4236.     }
  4237.     else if (STRNICMP(attr, "complete", attrlen) == 0)
  4238.     {
  4239.         if (val == NULL)
  4240.         {
  4241.         EMSG(_("E179: argument required for complete"));
  4242.         return FAIL;
  4243.         }
  4244.  
  4245.         for (i = 0; command_complete[i].expand != 0; ++i)
  4246.         if (STRLEN(command_complete[i].name) == vallen
  4247.             && STRNCMP(val, command_complete[i].name, vallen) == 0)
  4248.         {
  4249.             *compl = command_complete[i].expand;
  4250.             if (command_complete[i].expand == EXPAND_BUFFERS)
  4251.             *argt |= BUFNAME;
  4252.             else if (command_complete[i].expand == EXPAND_DIRECTORIES
  4253.                 || command_complete[i].expand == EXPAND_FILES)
  4254.             *argt |= XFILE;
  4255.             break;
  4256.         }
  4257.  
  4258.         if (command_complete[i].expand == 0)
  4259.         {
  4260.         EMSG2(_("E180: Invalid complete value: %s"), val);
  4261.         return FAIL;
  4262.         }
  4263.     }
  4264.     else
  4265.     {
  4266.         char_u ch = attr[len];
  4267.         attr[len] = '\0';
  4268.         EMSG2(_("E181: Invalid attribute: %s"), attr);
  4269.         attr[len] = ch;
  4270.         return FAIL;
  4271.     }
  4272.     }
  4273.  
  4274.     return OK;
  4275. }
  4276.  
  4277.     static void
  4278. ex_command(eap)
  4279.     exarg_T   *eap;
  4280. {
  4281.     char_u  *name;
  4282.     char_u  *end;
  4283.     char_u  *p;
  4284.     long    argt = 0;
  4285.     long    def = -1;
  4286.     int        flags = 0;
  4287.     int        compl = EXPAND_NOTHING;
  4288.     int        has_attr = (eap->arg[0] == '-');
  4289.  
  4290.     p = eap->arg;
  4291.  
  4292.     /* Check for attributes */
  4293.     while (*p == '-')
  4294.     {
  4295.     ++p;
  4296.     end = skiptowhite(p);
  4297.     if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl) == FAIL)
  4298.         return;
  4299.     p = skipwhite(end);
  4300.     }
  4301.  
  4302.     /* Get the name (if any) and skip to the following argument */
  4303.     name = p;
  4304.     if (ASCII_ISALPHA(*p))
  4305.     while (ASCII_ISALNUM(*p))
  4306.         ++p;
  4307.     if (!ends_excmd(*p) && !vim_iswhite(*p))
  4308.     {
  4309.     EMSG(_("E182: Invalid command name"));
  4310.     return;
  4311.     }
  4312.     end = p;
  4313.  
  4314.     /* If there is nothing after the name, and no attributes were specified,
  4315.      * we are listing commands
  4316.      */
  4317.     p = skipwhite(end);
  4318.     if (!has_attr && ends_excmd(*p))
  4319.     {
  4320.     uc_list(name, end - name);
  4321.     }
  4322.     else if (!ASCII_ISUPPER(*name))
  4323.     {
  4324.     EMSG(_("E183: User defined commands must start with an uppercase letter"));
  4325.     return;
  4326.     }
  4327.     else
  4328.     uc_add_command(name, end - name, p, argt, def, flags, compl,
  4329.                                 eap->forceit);
  4330. }
  4331.  
  4332. /*
  4333.  * ":comclear"
  4334.  */
  4335. /*ARGSUSED*/
  4336. /*
  4337.  * Clear all user commands, global and for current buffer.
  4338.  */
  4339.     static void
  4340. ex_comclear(eap)
  4341.     exarg_T    *eap;
  4342. {
  4343.     uc_clear(&ucmds);
  4344.     uc_clear(&curbuf->b_ucmds);
  4345. }
  4346.  
  4347. /*
  4348.  * Clear all user commands for "gap".
  4349.  */
  4350.     void
  4351. uc_clear(gap)
  4352.     garray_T    *gap;
  4353. {
  4354.     int        i;
  4355.     ucmd_T    *cmd;
  4356.  
  4357.     for (i = 0; i < gap->ga_len; ++i)
  4358.     {
  4359.     cmd = USER_CMD_GA(gap, i);
  4360.     vim_free(cmd->uc_name);
  4361.     vim_free(cmd->uc_rep);
  4362.     }
  4363.     ga_clear(gap);
  4364. }
  4365.  
  4366.     static void
  4367. ex_delcommand(eap)
  4368.     exarg_T    *eap;
  4369. {
  4370.     int        i = 0;
  4371.     ucmd_T    *cmd;
  4372.     int        cmp = -1;
  4373.     garray_T    *gap;
  4374.  
  4375.     gap = &curbuf->b_ucmds;
  4376.     for (;;)
  4377.     {
  4378.     cmd = USER_CMD_GA(gap, 0);
  4379.     for (i = 0; i < gap->ga_len; ++i)
  4380.     {
  4381.         cmp = STRCMP(eap->arg, cmd->uc_name);
  4382.         if (cmp <= 0)
  4383.         break;
  4384.         ++cmd;
  4385.     }
  4386.     if (gap == &ucmds || cmp == 0)
  4387.         break;
  4388.     gap = &ucmds;
  4389.     }
  4390.  
  4391.     if (cmp != 0)
  4392.     {
  4393.     EMSG2(_("E184: No such user-defined command: %s"), eap->arg);
  4394.     return;
  4395.     }
  4396.  
  4397.     vim_free(cmd->uc_name);
  4398.     vim_free(cmd->uc_rep);
  4399.  
  4400.     --gap->ga_len;
  4401.     ++gap->ga_room;
  4402.  
  4403.     if (i < gap->ga_len)
  4404.     mch_memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T));
  4405. }
  4406.  
  4407.     static char_u *
  4408. uc_split_args(arg, lenp)
  4409.     char_u *arg;
  4410.     size_t *lenp;
  4411. {
  4412.     char_u *buf;
  4413.     char_u *p;
  4414.     char_u *q;
  4415.     int len;
  4416.  
  4417.     /* Precalculate length */
  4418.     p = arg;
  4419.     len = 2; /* Initial and final quotes */
  4420.  
  4421.     while (*p)
  4422.     {
  4423.     if (p[0] == '\\' && vim_iswhite(p[1]))
  4424.     {
  4425.         len += 1;
  4426.         p += 2;
  4427.     }
  4428.     else if (*p == '\\' || *p == '"')
  4429.     {
  4430.         len += 2;
  4431.         p += 1;
  4432.     }
  4433.     else if (vim_iswhite(*p))
  4434.     {
  4435.         p = skipwhite(p);
  4436.         if (*p == NUL)
  4437.         break;
  4438.         len += 3; /* "," */
  4439.     }
  4440.     else
  4441.     {
  4442.         ++len;
  4443.         ++p;
  4444.     }
  4445.     }
  4446.  
  4447.     buf = alloc(len + 1);
  4448.     if (buf == NULL)
  4449.     {
  4450.     *lenp = 0;
  4451.     return buf;
  4452.     }
  4453.  
  4454.     p = arg;
  4455.     q = buf;
  4456.     *q++ = '"';
  4457.     while (*p)
  4458.     {
  4459.     if (p[0] == '\\' && vim_iswhite(p[1]))
  4460.     {
  4461.         *q++ = p[1];
  4462.         p += 2;
  4463.     }
  4464.     else if (*p == '\\' || *p == '"')
  4465.     {
  4466.         *q++ = '\\';
  4467.         *q++ = *p++;
  4468.     }
  4469.     else if (vim_iswhite(*p))
  4470.     {
  4471.         p = skipwhite(p);
  4472.         if (*p == NUL)
  4473.         break;
  4474.         *q++ = '"';
  4475.         *q++ = ',';
  4476.         *q++ = '"';
  4477.     }
  4478.     else
  4479.     {
  4480.         *q++ = *p++;
  4481.     }
  4482.     }
  4483.     *q++ = '"';
  4484.     *q = 0;
  4485.  
  4486.     *lenp = len;
  4487.     return buf;
  4488. }
  4489.  
  4490. /*
  4491.  * Check for a <> code in a user command.
  4492.  * "code" points to the '<'.  "len" the length of the <> (inclusive).
  4493.  * "buf" is where the result is to be added.
  4494.  * "split_buf" points to a buffer used for splitting, caller should free it.
  4495.  * "split_len" is the length of what "split_buf" contains.
  4496.  * Returns the length of the replacement, which has been added to "buf".
  4497.  * Returns -1 if there was no match, and only the "<" has been copied.
  4498.  */
  4499.     static size_t
  4500. uc_check_code(code, len, buf, cmd, eap, split_buf, split_len)
  4501.     char_u    *code;
  4502.     size_t    len;
  4503.     char_u    *buf;
  4504.     ucmd_T    *cmd;        /* the user command we're expanding */
  4505.     exarg_T    *eap;        /* ex arguments */
  4506.     char_u    **split_buf;
  4507.     size_t    *split_len;
  4508. {
  4509.     size_t    result = 0;
  4510.     char_u    *p = code + 1;
  4511.     size_t    l = len - 2;
  4512.     int        quote = 0;
  4513.     enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_REGISTER,
  4514.     ct_LT, ct_NONE } type = ct_NONE;
  4515.  
  4516.     if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-')
  4517.     {
  4518.     quote = (*p == 'q' || *p == 'Q') ? 1 : 2;
  4519.     p += 2;
  4520.     l -= 2;
  4521.     }
  4522.  
  4523.     if (STRNICMP(p, "args", l) == 0)
  4524.     type = ct_ARGS;
  4525.     else if (STRNICMP(p, "bang", l) == 0)
  4526.     type = ct_BANG;
  4527.     else if (STRNICMP(p, "count", l) == 0)
  4528.     type = ct_COUNT;
  4529.     else if (STRNICMP(p, "line1", l) == 0)
  4530.     type = ct_LINE1;
  4531.     else if (STRNICMP(p, "line2", l) == 0)
  4532.     type = ct_LINE2;
  4533.     else if (STRNICMP(p, "lt", l) == 0)
  4534.     type = ct_LT;
  4535.     else if (STRNICMP(p, "register", l) == 0)
  4536.     type = ct_REGISTER;
  4537.  
  4538.     switch (type)
  4539.     {
  4540.     case ct_ARGS:
  4541.     /* Simple case first */
  4542.     if (*eap->arg == NUL)
  4543.     {
  4544.         if (quote == 1)
  4545.         {
  4546.         result = 2;
  4547.         if (buf != NULL)
  4548.             STRCPY(buf, "''");
  4549.         }
  4550.         else
  4551.         result = 0;
  4552.         break;
  4553.     }
  4554.  
  4555.     switch (quote)
  4556.     {
  4557.     case 0: /* No quoting, no splitting */
  4558.         result = STRLEN(eap->arg);
  4559.         if (buf != NULL)
  4560.         STRCPY(buf, eap->arg);
  4561.         break;
  4562.     case 1: /* Quote, but don't split */
  4563.         result = STRLEN(eap->arg) + 2;
  4564.         for (p = eap->arg; *p; ++p)
  4565.         {
  4566.         if (*p == '\\' || *p == '"')
  4567.             ++result;
  4568.         }
  4569.  
  4570.         if (buf != NULL)
  4571.         {
  4572.         *buf++ = '"';
  4573.         for (p = eap->arg; *p; ++p)
  4574.         {
  4575.             if (*p == '\\' || *p == '"')
  4576.             *buf++ = '\\';
  4577.             *buf++ = *p;
  4578.         }
  4579.         *buf = '"';
  4580.         }
  4581.  
  4582.         break;
  4583.     case 2: /* Quote and split */
  4584.         /* This is hard, so only do it once, and cache the result */
  4585.         if (*split_buf == NULL)
  4586.         *split_buf = uc_split_args(eap->arg, split_len);
  4587.  
  4588.         result = *split_len;
  4589.         if (buf != NULL && result != 0)
  4590.         STRCPY(buf, *split_buf);
  4591.  
  4592.         break;
  4593.     }
  4594.     break;
  4595.  
  4596.     case ct_BANG:
  4597.     result = eap->forceit ? 1 : 0;
  4598.     if (quote)
  4599.         result += 2;
  4600.     if (buf != NULL)
  4601.     {
  4602.         if (quote)
  4603.         *buf++ = '"';
  4604.         if (eap->forceit)
  4605.         *buf++ = '!';
  4606.         if (quote)
  4607.         *buf = '"';
  4608.     }
  4609.     break;
  4610.  
  4611.     case ct_LINE1:
  4612.     case ct_LINE2:
  4613.     case ct_COUNT:
  4614.     {
  4615.     char num_buf[20];
  4616.     long num = (type == ct_LINE1) ? eap->line1 :
  4617.            (type == ct_LINE2) ? eap->line2 :
  4618.            (eap->addr_count > 0) ? eap->line2 : cmd->uc_def;
  4619.     size_t num_len;
  4620.  
  4621.     sprintf(num_buf, "%ld", num);
  4622.     num_len = STRLEN(num_buf);
  4623.     result = num_len;
  4624.  
  4625.     if (quote)
  4626.         result += 2;
  4627.  
  4628.     if (buf != NULL)
  4629.     {
  4630.         if (quote)
  4631.         *buf++ = '"';
  4632.         STRCPY(buf, num_buf);
  4633.         buf += num_len;
  4634.         if (quote)
  4635.         *buf = '"';
  4636.     }
  4637.  
  4638.     break;
  4639.     }
  4640.  
  4641.     case ct_REGISTER:
  4642.     result = eap->regname ? 1 : 0;
  4643.     if (quote)
  4644.         result += 2;
  4645.     if (buf != NULL)
  4646.     {
  4647.         if (quote)
  4648.         *buf++ = '\'';
  4649.         if (eap->regname)
  4650.         *buf++ = eap->regname;
  4651.         if (quote)
  4652.         *buf = '\'';
  4653.     }
  4654.     break;
  4655.  
  4656.     case ct_LT:
  4657.     result = 1;
  4658.     if (buf != NULL)
  4659.         *buf = '<';
  4660.     break;
  4661.  
  4662.     default:
  4663.     /* Not recognized: just copy the '<' and return -1. */
  4664.     result = (size_t)-1;
  4665.     if (buf != NULL)
  4666.         *buf = '<';
  4667.     break;
  4668.     }
  4669.  
  4670.     return result;
  4671. }
  4672.  
  4673.     static void
  4674. do_ucmd(eap)
  4675.     exarg_T    *eap;
  4676. {
  4677.     char_u    *buf;
  4678.     char_u    *p;
  4679.     char_u    *q;
  4680.  
  4681.     char_u    *start;
  4682.     char_u    *end;
  4683.     size_t    len, totlen;
  4684.  
  4685.     size_t    split_len = 0;
  4686.     char_u    *split_buf = NULL;
  4687.     ucmd_T    *cmd;
  4688. #ifdef FEAT_EVAL
  4689.     scid_T    save_current_SID = current_SID;
  4690. #endif
  4691.  
  4692.     if (eap->cmdidx == CMD_USER)
  4693.     cmd = USER_CMD(eap->useridx);
  4694.     else
  4695.     cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx);
  4696.  
  4697.     /*
  4698.      * Replace <> in the command by the arguments.
  4699.      */
  4700.     buf = NULL;
  4701.     for (;;)
  4702.     {
  4703.     p = cmd->uc_rep;
  4704.     q = buf;
  4705.     totlen = 0;
  4706.     while ((start = vim_strchr(p, '<')) != NULL
  4707.            && (end = vim_strchr(start + 1, '>')) != NULL)
  4708.     {
  4709.         /* Include the '>' */
  4710.         ++end;
  4711.  
  4712.         /* Take everything up to the '<' */
  4713.         len = start - p;
  4714.         if (buf == NULL)
  4715.         totlen += len;
  4716.         else
  4717.         {
  4718.         mch_memmove(q, p, len);
  4719.         q += len;
  4720.         }
  4721.  
  4722.         len = uc_check_code(start, end - start, q, cmd, eap,
  4723.                  &split_buf, &split_len);
  4724.         if (len == (size_t)-1)
  4725.         {
  4726.         /* no match, continue after '<' */
  4727.         p = start + 1;
  4728.         len = 1;
  4729.         }
  4730.         else
  4731.         p = end;
  4732.         if (buf == NULL)
  4733.         totlen += len;
  4734.         else
  4735.         q += len;
  4736.     }
  4737.     if (buf != NULL)        /* second time here, finished */
  4738.     {
  4739.         STRCPY(q, p);
  4740.         break;
  4741.     }
  4742.  
  4743.     totlen += STRLEN(p);        /* Add on the trailing characters */
  4744.     buf = alloc((unsigned)(totlen + 1));
  4745.     if (buf == NULL)
  4746.     {
  4747.         vim_free(split_buf);
  4748.         return;
  4749.     }
  4750.     }
  4751.  
  4752. #ifdef FEAT_EVAL
  4753.     current_SID = cmd->uc_scriptID;
  4754. #endif
  4755.     (void)do_cmdline(buf, eap->getline, eap->cookie,
  4756.                    DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
  4757. #ifdef FEAT_EVAL
  4758.     current_SID = save_current_SID;
  4759. #endif
  4760.     vim_free(buf);
  4761.     vim_free(split_buf);
  4762. }
  4763.  
  4764. # if defined(FEAT_CMDL_COMPL) || defined(PROTO)
  4765.     static char_u *
  4766. get_user_command_name(idx)
  4767.     int        idx;
  4768. {
  4769.     return get_user_commands(NULL, idx - (int)CMD_SIZE);
  4770. }
  4771.  
  4772. /*
  4773.  * Function given to ExpandGeneric() to obtain the list of user command names.
  4774.  */
  4775. /*ARGSUSED*/
  4776.     char_u *
  4777. get_user_commands(xp, idx)
  4778.     expand_T    *xp;
  4779.     int        idx;
  4780. {
  4781.     if (idx < curbuf->b_ucmds.ga_len)
  4782.     return USER_CMD_GA(&curbuf->b_ucmds, idx)->uc_name;
  4783.     idx -= curbuf->b_ucmds.ga_len;
  4784.     if (idx < ucmds.ga_len)
  4785.     return USER_CMD(idx)->uc_name;
  4786.     return NULL;
  4787. }
  4788.  
  4789. /*
  4790.  * Function given to ExpandGeneric() to obtain the list of user command
  4791.  * attributes.
  4792.  */
  4793. /*ARGSUSED*/
  4794.     char_u *
  4795. get_user_cmd_flags(xp, idx)
  4796.     expand_T    *xp;
  4797.     int        idx;
  4798. {
  4799.     static char *user_cmd_flags[] =
  4800.     {"bang", "bar", "buffer", "complete", "count",
  4801.         "nargs", "range", "register"};
  4802.  
  4803.     if (idx >= sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0]))
  4804.     return NULL;
  4805.     return (char_u *)user_cmd_flags[idx];
  4806. }
  4807.  
  4808. /*
  4809.  * Function given to ExpandGeneric() to obtain the list of values for -nargs.
  4810.  */
  4811. /*ARGSUSED*/
  4812.     char_u *
  4813. get_user_cmd_nargs(xp, idx)
  4814.     expand_T    *xp;
  4815.     int        idx;
  4816. {
  4817.     static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"};
  4818.  
  4819.     if (idx >= sizeof(user_cmd_nargs) / sizeof(user_cmd_nargs[0]))
  4820.     return NULL;
  4821.     return (char_u *)user_cmd_nargs[idx];
  4822. }
  4823.  
  4824. /*
  4825.  * Function given to ExpandGeneric() to obtain the list of values for -complete.
  4826.  */
  4827. /*ARGSUSED*/
  4828.     char_u *
  4829. get_user_cmd_complete(xp, idx)
  4830.     expand_T    *xp;
  4831.     int        idx;
  4832. {
  4833.     return (char_u *)command_complete[idx].name;
  4834. }
  4835. # endif /* FEAT_CMDL_COMPL */
  4836.  
  4837. #endif    /* FEAT_USR_CMDS */
  4838.  
  4839.     static void
  4840. ex_colorscheme(eap)
  4841.     exarg_T    *eap;
  4842. {
  4843.     if (load_colors(eap->arg) == FAIL)
  4844.     EMSG2(_("E185: Cannot find color scheme %s"), eap->arg);
  4845. }
  4846.  
  4847.     static void
  4848. ex_highlight(eap)
  4849.     exarg_T    *eap;
  4850. {
  4851.     if (*eap->arg == NUL && eap->cmd[2] == '!')
  4852.     MSG(_("Greetings, Vim user!"));
  4853.     do_highlight(eap->arg, eap->forceit, FALSE);
  4854. }
  4855.  
  4856.  
  4857. /*
  4858.  * Call this function if we thought we were going to exit, but we won't
  4859.  * (because of an error).  May need to restore the terminal mode.
  4860.  */
  4861.     void
  4862. not_exiting()
  4863. {
  4864.     exiting = FALSE;
  4865.     settmode(TMODE_RAW);
  4866. }
  4867.  
  4868. /*
  4869.  * ":quit": quit current window, quit Vim if closed the last window.
  4870.  */
  4871.     static void
  4872. ex_quit(eap)
  4873.     exarg_T    *eap;
  4874. {
  4875. #ifdef FEAT_CMDWIN
  4876.     if (cmdwin_type != 0)
  4877.     {
  4878.     cmdwin_result = Ctrl_C;
  4879.     return;
  4880.     }
  4881. #endif
  4882.  
  4883.     /*
  4884.      * If there are more files or windows we won't exit.
  4885.      */
  4886.     if (check_more(FALSE, eap->forceit) == OK && only_one_window())
  4887.     exiting = TRUE;
  4888.     if ((!P_HID(curbuf)
  4889.         && check_changed(curbuf, p_awa, FALSE, eap->forceit, FALSE))
  4890.         || check_more(TRUE, eap->forceit) == FAIL
  4891.         || (only_one_window() && check_changed_any(eap->forceit)))
  4892.     {
  4893.     not_exiting();
  4894.     }
  4895.     else
  4896.     {
  4897. #ifdef FEAT_WINDOWS
  4898.     if (only_one_window())        /* quit last window */
  4899. #endif
  4900.         getout(0);
  4901. #ifdef FEAT_WINDOWS
  4902. # ifdef FEAT_GUI
  4903.     need_mouse_correct = TRUE;
  4904. # endif
  4905.     /* close window; may free buffer */
  4906.     win_close(curwin, !P_HID(curwin->w_buffer) || eap->forceit);
  4907. #endif
  4908.     }
  4909. }
  4910.  
  4911. /*
  4912.  * ":cquit".
  4913.  */
  4914. /*ARGSUSED*/
  4915.     static void
  4916. ex_cquit(eap)
  4917.     exarg_T    *eap;
  4918. {
  4919.     getout(1);    /* this does not always pass on the exit code to the Manx
  4920.            compiler. why? */
  4921. }
  4922.  
  4923. /*
  4924.  * ":qall": try to quit all windows
  4925.  */
  4926.     static void
  4927. ex_quit_all(eap)
  4928.     exarg_T    *eap;
  4929. {
  4930. # ifdef FEAT_CMDWIN
  4931.     if (cmdwin_type != 0)
  4932.     {
  4933.     if (eap->forceit)
  4934.         cmdwin_result = K_XF1;    /* ex_window() takes care of this */
  4935.     else
  4936.         cmdwin_result = K_XF2;
  4937.     return;
  4938.     }
  4939. # endif
  4940.     exiting = TRUE;
  4941.     if (eap->forceit || !check_changed_any(FALSE))
  4942.     getout(0);
  4943.     not_exiting();
  4944. }
  4945.  
  4946. #ifdef FEAT_WINDOWS
  4947. /*
  4948.  * ":close": close current window, unless it is the last one
  4949.  */
  4950.     static void
  4951. ex_close(eap)
  4952.     exarg_T    *eap;
  4953. {
  4954. # ifdef FEAT_CMDWIN
  4955.     if (cmdwin_type != 0)
  4956.     cmdwin_result = K_IGNORE;
  4957.     else
  4958. # endif
  4959.     ex_win_close(eap, curwin);
  4960. }
  4961.  
  4962.     static void
  4963. ex_win_close(eap, win)
  4964.     exarg_T    *eap;
  4965.     win_T    *win;
  4966. {
  4967.     int        need_hide;
  4968.     buf_T    *buf = win->w_buffer;
  4969.  
  4970.     need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
  4971.     if (need_hide && !P_HID(buf) && !eap->forceit)
  4972.     {
  4973. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  4974.     if ((p_confirm || cmdmod.confirm) && p_write)
  4975.     {
  4976.         dialog_changed(buf, FALSE);
  4977.         if (buf_valid(buf) && bufIsChanged(buf))
  4978.         return;
  4979.         need_hide = FALSE;
  4980.     }
  4981.     else
  4982. #endif
  4983.     {
  4984.         EMSG(_(e_nowrtmsg));
  4985.         return;
  4986.     }
  4987.     }
  4988.  
  4989. #ifdef FEAT_GUI
  4990.     need_mouse_correct = TRUE;
  4991. #endif
  4992.     /* free buffer when not hiding it or when it's a scratch buffer */
  4993.     win_close(win, !need_hide && !P_HID(buf));
  4994. }
  4995.  
  4996. #ifdef FEAT_QUICKFIX
  4997. /*
  4998.  * ":pclose": Close any preview window.
  4999.  */
  5000.     static void
  5001. ex_pclose(eap)
  5002.     exarg_T    *eap;
  5003. {
  5004.     win_T    *win;
  5005.  
  5006.     for (win = firstwin; win != NULL; win = win->w_next)
  5007.     if (win->w_p_pvw)
  5008.     {
  5009.         ex_win_close(eap, win);
  5010.         break;
  5011.     }
  5012. }
  5013. #endif
  5014.  
  5015. /*
  5016.  * ":only".
  5017.  */
  5018.     static void
  5019. ex_only(eap)
  5020.     exarg_T    *eap;
  5021. {
  5022. # ifdef FEAT_GUI
  5023.     need_mouse_correct = TRUE;
  5024. # endif
  5025.     close_others(TRUE, eap->forceit);
  5026. }
  5027.  
  5028. /*
  5029.  * ":all" and ":sall".
  5030.  */
  5031.     static void
  5032. ex_all(eap)
  5033.     exarg_T    *eap;
  5034. {
  5035.     if (eap->addr_count == 0)
  5036.     eap->line2 = 9999;
  5037.     do_arg_all((int)eap->line2, eap->forceit);
  5038. }
  5039. #endif /* FEAT_WINDOWS */
  5040.  
  5041.     static void
  5042. ex_hide(eap)
  5043.     exarg_T    *eap;
  5044. {
  5045.     if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL)
  5046.     eap->errmsg = e_invarg;
  5047.     else
  5048.     {
  5049.     /* ":hide" or ":hide | cmd": hide current window */
  5050.     eap->nextcmd = check_nextcmd(eap->arg);
  5051. #ifdef FEAT_WINDOWS
  5052.     if (!eap->skip)
  5053.     {
  5054. # ifdef FEAT_GUI
  5055.         need_mouse_correct = TRUE;
  5056. # endif
  5057.         win_close(curwin, FALSE);    /* don't free buffer */
  5058.     }
  5059. #endif
  5060.     }
  5061. }
  5062.  
  5063. /*
  5064.  * ":stop" and ":suspend": Suspend Vim.
  5065.  */
  5066.     static void
  5067. ex_stop(eap)
  5068.     exarg_T    *eap;
  5069. {
  5070.     /*
  5071.      * Disallow suspending for "rvim".
  5072.      */
  5073.     if (!check_restricted()
  5074. #ifdef WIN3264
  5075.     /*
  5076.      * Check if external commands are allowed now.
  5077.      */
  5078.     && can_end_termcap_mode(TRUE)
  5079. #endif
  5080.                     )
  5081.     {
  5082.     if (!eap->forceit)
  5083.         autowrite_all();
  5084.     windgoto((int)Rows - 1, 0);
  5085.     out_char('\n');
  5086.     out_flush();
  5087.     stoptermcap();
  5088.     out_flush();        /* needed for SUN to restore xterm buffer */
  5089. #ifdef FEAT_TITLE
  5090.     mch_restore_title(3);    /* restore window titles */
  5091. #endif
  5092.     ui_suspend();        /* call machine specific function */
  5093. #ifdef FEAT_TITLE
  5094.     maketitle();
  5095.     resettitle();        /* force updating the title */
  5096. #endif
  5097.     starttermcap();
  5098.     scroll_start();        /* scroll screen before redrawing */
  5099.     redraw_later_clear();
  5100.     shell_resized();    /* may have resized window */
  5101.     }
  5102. }
  5103.  
  5104. /*
  5105.  * ":exit", ":xit" and ":wq": Write file and exit Vim.
  5106.  */
  5107.     static void
  5108. ex_exit(eap)
  5109.     exarg_T    *eap;
  5110. {
  5111. #ifdef FEAT_CMDWIN
  5112.     if (cmdwin_type != 0)
  5113.     {
  5114.     cmdwin_result = Ctrl_C;
  5115.     return;
  5116.     }
  5117. #endif
  5118.  
  5119.     /*
  5120.      * if more files or windows we won't exit
  5121.      */
  5122.     if (check_more(FALSE, eap->forceit) == OK && only_one_window())
  5123.     exiting = TRUE;
  5124.     if (       ((eap->cmdidx == CMD_wq
  5125.             || curbufIsChanged())
  5126.         && do_write(eap) == FAIL)
  5127.         || check_more(TRUE, eap->forceit) == FAIL
  5128.         || (only_one_window() && check_changed_any(eap->forceit)))
  5129.     {
  5130.     not_exiting();
  5131.     }
  5132.     else
  5133.     {
  5134. #ifdef FEAT_WINDOWS
  5135.     if (only_one_window())        /* quit last window, exit Vim */
  5136. #endif
  5137.         getout(0);
  5138. #ifdef FEAT_WINDOWS
  5139. # ifdef FEAT_GUI
  5140.     need_mouse_correct = TRUE;
  5141. # endif
  5142.     /* quit current window, may free buffer */
  5143.     win_close(curwin, !P_HID(curwin->w_buffer));
  5144. #endif
  5145.     }
  5146. }
  5147.  
  5148. /*
  5149.  * ":print", ":list", ":number".
  5150.  */
  5151.     static void
  5152. ex_print(eap)
  5153.     exarg_T    *eap;
  5154. {
  5155.     int        save_list = 0;        /* init for GCC */
  5156.  
  5157.     if (eap->cmdidx == CMD_list)
  5158.     {
  5159.     save_list = curwin->w_p_list;
  5160.     curwin->w_p_list = 1;
  5161.     }
  5162.  
  5163.     for ( ;!got_int; ui_breakcheck())
  5164.     {
  5165.     print_line(eap->line1,
  5166.            (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound));
  5167.     if (++eap->line1 > eap->line2)
  5168.         break;
  5169.     out_flush();        /* show one line at a time */
  5170.     }
  5171.     setpcmark();
  5172.     /* put cursor at last line */
  5173.     curwin->w_cursor.lnum = eap->line2;
  5174.     beginline(BL_SOL | BL_FIX);
  5175.  
  5176.     ex_no_reprint = TRUE;
  5177.  
  5178.     if (eap->cmdidx == CMD_list)
  5179.     curwin->w_p_list = save_list;
  5180. }
  5181.  
  5182. #ifdef FEAT_BYTEOFF
  5183.     static void
  5184. ex_goto(eap)
  5185.     exarg_T    *eap;
  5186. {
  5187.     goto_byte(eap->line2);
  5188. }
  5189. #endif
  5190.  
  5191. /*
  5192.  * ":shell".
  5193.  */
  5194. /*ARGSUSED*/
  5195.     static void
  5196. ex_shell(eap)
  5197.     exarg_T    *eap;
  5198. {
  5199.     do_shell(NULL, 0);
  5200. }
  5201.  
  5202. #if (defined(FEAT_WINDOWS) && defined(HAVE_DROP_FILE)) || defined(PROTO)
  5203.  
  5204. /*
  5205.  * Handle a file drop. The code is here because a drop is *nearly* like an
  5206.  * :args command, but not quite (we have a list of exact filenames, so we
  5207.  * don't want to (a) parse a command line, or (b) expand wildcards. So the
  5208.  * code is very similar to :args and hence needs access to a lot of the static
  5209.  * functions in this file.
  5210.  *
  5211.  * The list should be allocated using vim_alloc(), as should each item in the
  5212.  * list. This function takes over responsibility for freeing the list.
  5213.  *
  5214.  * XXX The list is made into the arggument list. This is freed using
  5215.  * FreeWild(), which does a series of vim_free() calls, unless the two defines
  5216.  * __EMX__ and __ALWAYS_HAS_TRAILING_NUL_POINTER are set. In this case, a
  5217.  * routine _fnexplodefree() is used. This may cause problems, but as the drop
  5218.  * file functionality is (currently) not in EMX this is not presently a
  5219.  * problem.
  5220.  */
  5221.     void
  5222. handle_drop(filec, filev, split)
  5223.     int        filec;        /* the number of files dropped */
  5224.     char_u    **filev;    /* the list of files dropped */
  5225.     int        split;        /* force splitting the window */
  5226. {
  5227.     exarg_T    ea;
  5228.  
  5229. #ifdef FEAT_CMDWIN
  5230.     if (cmdwin_type != 0)
  5231.     return;
  5232. #endif
  5233.  
  5234.     /* Check whether the current buffer is changed. If so, we will need
  5235.      * to split the current window or data could be lost.
  5236.      * We don't need to check if the 'hidden' option is set, as in this
  5237.      * case the buffer won't be lost.
  5238.      */
  5239.     if (!P_HID(curbuf) && !split)
  5240.     {
  5241.     ++emsg_off;
  5242.     split = check_changed(curbuf, TRUE, FALSE, FALSE, FALSE);
  5243.     --emsg_off;
  5244.     }
  5245.     if (split)
  5246.     {
  5247.     if (win_split(0, 0) == FAIL)
  5248.         return;
  5249.  
  5250.     /* When splitting the window, create a new alist.  Otherwise the
  5251.      * existing one is overwritten. */
  5252.     alist_unlink(curwin->w_alist);
  5253.     alist_new();
  5254.     }
  5255.  
  5256.     /*
  5257.      * Set up the new argument list.
  5258.      */
  5259.     alist_set(ALIST(curwin), filec, filev, FALSE);
  5260.  
  5261.     /*
  5262.      * Move to the first file.
  5263.      */
  5264.     /* Fake up a minimal "next" command for do_argfile() */
  5265.     ea.cmd = (char_u *)"next";
  5266.     ea.forceit = FALSE;
  5267.     ea.do_ecmd_cmd = NULL;
  5268.     ea.do_ecmd_lnum = 0;
  5269.     ea.force_ff = 0;
  5270. # ifdef FEAT_MBYTE
  5271.     ea.force_enc = 0;
  5272. # endif
  5273.     do_argfile(&ea, 0);
  5274. }
  5275. #endif
  5276.  
  5277. static void alist_clear __ARGS((alist_T *al));
  5278. /*
  5279.  * Clear an argument list: free all file names and reset it to zero entries.
  5280.  */
  5281.     static void
  5282. alist_clear(al)
  5283.     alist_T    *al;
  5284. {
  5285.     while (--al->al_ga.ga_len >= 0)
  5286.     vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname);
  5287.     ga_clear(&al->al_ga);
  5288. }
  5289.  
  5290. /*
  5291.  * Init an argument list.
  5292.  */
  5293.     void
  5294. alist_init(al)
  5295.     alist_T    *al;
  5296. {
  5297.     ga_init2(&al->al_ga, (int)sizeof(aentry_T), 5);
  5298. }
  5299.  
  5300. #if defined(FEAT_WINDOWS) || defined(PROTO)
  5301.  
  5302. /*
  5303.  * Remove a reference from an argument list.
  5304.  * Ignored when the argument list is the global one.
  5305.  * If the argument list is no longer used by any window, free it.
  5306.  */
  5307.     void
  5308. alist_unlink(al)
  5309.     alist_T    *al;
  5310. {
  5311.     if (al != &global_alist && --al->al_refcount <= 0)
  5312.     {
  5313.     alist_clear(al);
  5314.     vim_free(al);
  5315.     }
  5316. }
  5317.  
  5318. # if defined(FEAT_LISTCMDS) || defined(HAVE_DROP_FILE) || defined(PROTO)
  5319. /*
  5320.  * Create a new argument list and use it for the current window.
  5321.  */
  5322.     void
  5323. alist_new()
  5324. {
  5325.     curwin->w_alist = (alist_T *)alloc((unsigned)sizeof(alist_T));
  5326.     if (curwin->w_alist == NULL)
  5327.     {
  5328.     curwin->w_alist = &global_alist;
  5329.     ++global_alist.al_refcount;
  5330.     }
  5331.     else
  5332.     {
  5333.     curwin->w_alist->al_refcount = 1;
  5334.     alist_init(curwin->w_alist);
  5335.     }
  5336. }
  5337. # endif
  5338. #endif
  5339.  
  5340. #if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) || defined(PROTO)
  5341. /*
  5342.  * Expand the file names in the global argument list.
  5343.  */
  5344.     void
  5345. alist_expand()
  5346. {
  5347.     char_u    **old_arg_files;
  5348.     char_u    **new_arg_files;
  5349.     int        new_arg_file_count;
  5350.     char_u    *save_p_su = p_su;
  5351.     int        i;
  5352.  
  5353.     /* Don't use 'suffixes' here.  This should work like the shell did the
  5354.      * expansion.  Also, the vimrc file isn't read yet, thus the user
  5355.      * can't set the options. */
  5356.     p_su = empty_option;
  5357.     old_arg_files = (char_u **)alloc((unsigned)(sizeof(char_u *) * GARGCOUNT));
  5358.     if (old_arg_files != NULL)
  5359.     {
  5360.     for (i = 0; i < GARGCOUNT; ++i)
  5361.         old_arg_files[i] = GARGLIST[i].ae_fname;
  5362.     if (expand_wildcards(GARGCOUNT, old_arg_files,
  5363.             &new_arg_file_count, &new_arg_files,
  5364.             EW_FILE|EW_NOTFOUND|EW_ADDSLASH) == OK
  5365.         && new_arg_file_count > 0)
  5366.     {
  5367.         alist_set(&global_alist, new_arg_file_count, new_arg_files, TRUE);
  5368.     }
  5369.     vim_free(old_arg_files);
  5370.     }
  5371.     p_su = save_p_su;
  5372. }
  5373. #endif
  5374.  
  5375. /*
  5376.  * Set the argument list for the current window.
  5377.  * Takes over the allocated files[] and the allocated fnames in it.
  5378.  */
  5379.     void
  5380. alist_set(al, count, files, use_curbuf)
  5381.     alist_T    *al;
  5382.     int        count;
  5383.     char_u    **files;
  5384.     int        use_curbuf;
  5385. {
  5386.     int        i;
  5387.  
  5388.     alist_clear(al);
  5389.     if (ga_grow(&al->al_ga, count) == OK)
  5390.     {
  5391.     for (i = 0; i < count; ++i)
  5392.         alist_add(al, files[i], use_curbuf ? 2 : 1);
  5393.     vim_free(files);
  5394.     }
  5395.     else
  5396.     FreeWild(count, files);
  5397. #ifdef FEAT_WINDOWS
  5398.     if (al == &global_alist)
  5399. #endif
  5400.     arg_had_last = FALSE;
  5401. }
  5402.  
  5403. /*
  5404.  * Add file "fname" to argument list "al".
  5405.  * "fname" must have been allocated and "al" must have been checked for room.
  5406.  */
  5407.     void
  5408. alist_add(al, fname, set_fnum)
  5409.     alist_T    *al;
  5410.     char_u    *fname;
  5411.     int        set_fnum;    /* 1: set buffer number; 2: re-use curbuf */
  5412. {
  5413.     if (fname == NULL)        /* don't add NULL file names */
  5414.     return;
  5415. #ifdef BACKSLASH_IN_FILENAME
  5416.     slash_adjust(fname);
  5417. #endif
  5418.     AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname;
  5419.     if (set_fnum > 0)
  5420.     AARGLIST(al)[al->al_ga.ga_len].ae_fnum =
  5421.         buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
  5422.     ++al->al_ga.ga_len;
  5423.     --al->al_ga.ga_room;
  5424. }
  5425.  
  5426. #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
  5427. /*
  5428.  * Adjust slashes in file names.  Called after 'shellslash' was set.
  5429.  */
  5430.     void
  5431. alist_slash_adjust()
  5432. {
  5433.     int        i;
  5434. # ifdef FEAT_WINDOWS
  5435.     win_T    *wp;
  5436. # endif
  5437.  
  5438.     for (i = 0; i < GARGCOUNT; ++i)
  5439.     if (GARGLIST[i].ae_fname != NULL)
  5440.         slash_adjust(GARGLIST[i].ae_fname);
  5441. # ifdef FEAT_WINDOWS
  5442.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  5443.     if (wp->w_alist != &global_alist)
  5444.         for (i = 0; i < WARGCOUNT(wp); ++i)
  5445.         if (WARGLIST(wp)[i].ae_fname != NULL)
  5446.             slash_adjust(WARGLIST(wp)[i].ae_fname);
  5447. # endif
  5448. }
  5449. #endif
  5450.  
  5451. /*
  5452.  * ":preserve".
  5453.  */
  5454. /*ARGSUSED*/
  5455.     static void
  5456. ex_preserve(eap)
  5457.     exarg_T    *eap;
  5458. {
  5459.     ml_preserve(curbuf, TRUE);
  5460. }
  5461.  
  5462. /*
  5463.  * ":recover".
  5464.  */
  5465.     static void
  5466. ex_recover(eap)
  5467.     exarg_T    *eap;
  5468. {
  5469.     if (!check_changed(curbuf, p_awa, TRUE, eap->forceit, FALSE)
  5470.         && (*eap->arg == NUL || setfname(eap->arg, NULL, TRUE) == OK))
  5471.     ml_recover();
  5472. }
  5473.  
  5474. /*
  5475.  * Command modifier used in a wrong way.
  5476.  */
  5477.     static void
  5478. ex_wrongmodifier(eap)
  5479.     exarg_T    *eap;
  5480. {
  5481.     eap->errmsg = e_invcmd;
  5482. }
  5483.  
  5484. #ifdef FEAT_WINDOWS
  5485. /*
  5486.  * :sview [+command] file    split window with new file, read-only
  5487.  * :split [[+command] file]    split window with current or new file
  5488.  * :vsplit [[+command] file]    split window vertically with current or new file
  5489.  * :new [[+command] file]    split window with no or new file
  5490.  * :vnew [[+command] file]    split vertically window with no or new file
  5491.  * :sfind [+command] file    split window with file in 'path'
  5492.  */
  5493.     static void
  5494. ex_splitview(eap)
  5495.     exarg_T    *eap;
  5496. {
  5497.     win_T    *old_curwin;
  5498. #if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE)
  5499.     char_u    *fname = NULL;
  5500. #endif
  5501.  
  5502. #ifndef FEAT_VERTSPLIT
  5503.     if (eap->cmdidx == CMD_vsplit || eap->cmdidx == CMD_vnew)
  5504.     {
  5505.     ex_ni(eap);
  5506.     return;
  5507.     }
  5508. #endif
  5509.  
  5510.     old_curwin = curwin;
  5511. #ifdef FEAT_GUI
  5512.     need_mouse_correct = TRUE;
  5513. #endif
  5514.  
  5515. #ifdef FEAT_QUICKFIX
  5516.     /* A ":split" in the quickfix window works like ":new".  Don't want two
  5517.      * quickfix windows. */
  5518.     if (bt_quickfix(curbuf))
  5519.     {
  5520.     if (eap->cmdidx == CMD_split)
  5521.         eap->cmdidx = CMD_new;
  5522. # ifdef FEAT_VERTSPLIT
  5523.     if (eap->cmdidx == CMD_vsplit)
  5524.         eap->cmdidx = CMD_vnew;
  5525. # endif
  5526.     }
  5527. #endif
  5528.  
  5529. #ifdef FEAT_SEARCHPATH
  5530.     if (eap->cmdidx == CMD_sfind)
  5531.     {
  5532.     fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
  5533.                       FNAME_MESS, TRUE, curbuf->b_ffname);
  5534.     if (fname == NULL)
  5535.         goto theend;
  5536.     eap->arg = fname;
  5537.     }
  5538. # ifdef FEAT_BROWSE
  5539.     else
  5540. # endif
  5541. #endif
  5542. #ifdef FEAT_BROWSE
  5543.     if (cmdmod.browse
  5544. # ifdef FEAT_VERTSPLIT
  5545.         && eap->cmdidx != CMD_vnew
  5546. #endif
  5547.         && eap->cmdidx != CMD_new)
  5548.     {
  5549.     fname = do_browse(FALSE, (char_u *)_("Edit File in new window"),
  5550.                       NULL, NULL, eap->arg, NULL, curbuf);
  5551.     if (fname == NULL)
  5552.         goto theend;
  5553.     eap->arg = fname;
  5554.     }
  5555. #endif
  5556.     if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0,
  5557.                      *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL)
  5558.     do_exedit(eap, old_curwin);
  5559.  
  5560. #if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE)
  5561. theend:
  5562.     vim_free(fname);
  5563. #endif
  5564. }
  5565. #endif
  5566.  
  5567. /*
  5568.  * ":mode": Set screen mode.
  5569.  * If no argument given, just get the screen size and redraw.
  5570.  */
  5571.     static void
  5572. ex_mode(eap)
  5573.     exarg_T    *eap;
  5574. {
  5575.     if (*eap->arg == NUL)
  5576.     shell_resized();
  5577.     else
  5578.     mch_screenmode(eap->arg);
  5579. }
  5580.  
  5581. #ifdef FEAT_WINDOWS
  5582. /*
  5583.  * ":resize".
  5584.  * set, increment or decrement current window height
  5585.  */
  5586.     static void
  5587. ex_resize(eap)
  5588.     exarg_T    *eap;
  5589. {
  5590.     int        n;
  5591.  
  5592. #ifdef FEAT_GUI
  5593.     need_mouse_correct = TRUE;
  5594. #endif
  5595.     n = atol((char *)eap->arg);
  5596. #ifdef FEAT_VERTSPLIT
  5597.     if (cmdmod.split & WSP_VERT)
  5598.     {
  5599.     if (*eap->arg == '-' || *eap->arg == '+')
  5600.         n += W_WIDTH(curwin);
  5601.     else if (n == 0)        /* default is very wide */
  5602.         n = 9999;
  5603.     win_setwidth((int)n);
  5604.     }
  5605.     else
  5606. #endif
  5607.     {
  5608.     if (*eap->arg == '-' || *eap->arg == '+')
  5609.         n += curwin->w_height;
  5610.     else if (n == 0)        /* default is very high */
  5611.         n = 9999;
  5612.     win_setheight((int)n);
  5613.     }
  5614. }
  5615. #endif
  5616.  
  5617. /*
  5618.  * ":find [+command] <file>" command.
  5619.  */
  5620.     static void
  5621. ex_find(eap)
  5622.     exarg_T    *eap;
  5623. {
  5624. #ifdef FEAT_SEARCHPATH
  5625.     char_u    *fname;
  5626.     int        count;
  5627.  
  5628.     fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
  5629.                               TRUE, curbuf->b_ffname);
  5630.     if (eap->addr_count > 0)
  5631.     {
  5632.     /* Repeat finding the file "count" times.  This matters when it
  5633.      * appears several times in the path. */
  5634.     count = eap->line2;
  5635.     while (fname != NULL && --count > 0)
  5636.     {
  5637.         vim_free(fname);
  5638.         fname = find_file_in_path(NULL, 0, FNAME_MESS,
  5639.                              FALSE, curbuf->b_ffname);
  5640.     }
  5641.     }
  5642.  
  5643.     if (fname != NULL)
  5644.     {
  5645.     eap->arg = fname;
  5646. #endif
  5647.     do_exedit(eap, NULL);
  5648. #ifdef FEAT_SEARCHPATH
  5649.     vim_free(fname);
  5650.     }
  5651. #endif
  5652. }
  5653.  
  5654. /*
  5655.  * ":edit", ":badd".
  5656.  */
  5657.     static void
  5658. ex_edit(eap)
  5659.     exarg_T    *eap;
  5660. {
  5661.     do_exedit(eap, NULL);
  5662. }
  5663.  
  5664. /*
  5665.  * ":edit <file>" command and alikes.
  5666.  */
  5667. /*ARGSUSED*/
  5668.     void
  5669. do_exedit(eap, old_curwin)
  5670.     exarg_T    *eap;
  5671.     win_T    *old_curwin;        /* curwin before doing a split or NULL */
  5672. {
  5673.     int        n;
  5674. #ifdef FEAT_WINDOWS
  5675.     int        need_hide;
  5676. #endif
  5677.  
  5678.     /*
  5679.      * ":vi" command ends Ex mode.
  5680.      */
  5681.     if (exmode_active && (eap->cmdidx == CMD_visual
  5682.                         || eap->cmdidx == CMD_view))
  5683.     {
  5684.     exmode_active = FALSE;
  5685.     if (*eap->arg == NUL)
  5686.         return;
  5687.     }
  5688.  
  5689.     if ((eap->cmdidx == CMD_new
  5690. #ifdef FEAT_VERTSPLIT
  5691.         || eap->cmdidx == CMD_vnew
  5692. #endif
  5693.         ) && *eap->arg == NUL)
  5694.     {
  5695.     /* ":new" without argument: edit an new empty buffer */
  5696.     setpcmark();
  5697.     (void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE,
  5698.                    ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0));
  5699.     }
  5700.     else if ((eap->cmdidx != CMD_split
  5701. #ifdef FEAT_VERTSPLIT
  5702.         && eap->cmdidx != CMD_vsplit
  5703. #endif
  5704.         )
  5705.         || *eap->arg != NUL
  5706. #ifdef FEAT_BROWSE
  5707.         || cmdmod.browse
  5708. #endif
  5709.         )
  5710.     {
  5711.     n = readonlymode;
  5712.     if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview)
  5713.         readonlymode = TRUE;
  5714.     setpcmark();
  5715.     if (do_ecmd(0, (eap->cmdidx == CMD_enew ? NULL : eap->arg),
  5716.             NULL, eap, eap->do_ecmd_lnum,
  5717.             (P_HID(curbuf) ? ECMD_HIDE : 0)
  5718.             + (eap->forceit ? ECMD_FORCEIT : 0)
  5719. #ifdef FEAT_LISTCMDS
  5720.             + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0 )
  5721. #endif
  5722.             ) == FAIL)
  5723.     {
  5724.         /* Editing the file failed.  If the window was split, close it. */
  5725. #ifdef FEAT_WINDOWS
  5726.         if (old_curwin != NULL)
  5727.         {
  5728.         need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1);
  5729.         if (!need_hide || P_HID(curbuf))
  5730.         {
  5731. # ifdef FEAT_GUI
  5732.             need_mouse_correct = TRUE;
  5733. # endif
  5734.             win_close(curwin, !need_hide && !P_HID(curbuf));
  5735.         }
  5736.         }
  5737. #endif
  5738.     }
  5739.     else if (readonlymode && curbuf->b_nwindows == 1)
  5740.     {
  5741.         /* When editing an already visited buffer, 'readonly' won't be set
  5742.          * but the previous value is kept.  With ":view" and ":sview" we
  5743.          * want the  file to be readonly, except when another window is
  5744.          * editing the same buffer. */
  5745.         curbuf->b_p_ro = TRUE;
  5746.     }
  5747.     readonlymode = n;
  5748.     }
  5749.     else
  5750.     {
  5751.     if (eap->do_ecmd_cmd != NULL)
  5752.         do_cmdline_cmd(eap->do_ecmd_cmd);
  5753. #ifdef FEAT_TITLE
  5754.     n = curwin->w_arg_idx_invalid;
  5755. #endif
  5756.     check_arg_idx(curwin);
  5757. #ifdef FEAT_TITLE
  5758.     if (n != curwin->w_arg_idx_invalid)
  5759.         maketitle();
  5760. #endif
  5761.     }
  5762.  
  5763. #ifdef FEAT_WINDOWS
  5764.     /*
  5765.      * if ":split file" worked, set alternate file name in old window to new
  5766.      * file
  5767.      */
  5768.     if (old_curwin != NULL
  5769.         && *eap->arg != NUL
  5770.         && curwin != old_curwin
  5771.         && win_valid(old_curwin)
  5772.         && old_curwin->w_buffer != curbuf)
  5773.     old_curwin->w_alt_fnum = curbuf->b_fnum;
  5774. #endif
  5775.  
  5776.     ex_no_reprint = TRUE;
  5777. }
  5778.  
  5779. #ifndef FEAT_GUI
  5780. /*
  5781.  * ":gui" and ":gvim" when there is no GUI.
  5782.  */
  5783.     static void
  5784. ex_nogui(eap)
  5785.     exarg_T    *eap;
  5786. {
  5787.     eap->errmsg = e_nogvim;
  5788. }
  5789. #endif
  5790.  
  5791. #if defined(FEAT_GUI_W32) && defined(FEAT_MENU) && defined(FEAT_TEAROFF)
  5792.     static void
  5793. ex_tearoff(eap)
  5794.     exarg_T    *eap;
  5795. {
  5796.     gui_make_tearoff(eap->arg);
  5797. }
  5798. #endif
  5799.  
  5800. #if defined(FEAT_GUI_MSWIN) && defined(FEAT_MENU)
  5801.     static void
  5802. ex_popup(eap)
  5803.     exarg_T    *eap;
  5804. {
  5805.     gui_make_popup(eap->arg);
  5806. }
  5807. #endif
  5808.  
  5809. /*ARGSUSED*/
  5810.     static void
  5811. ex_swapname(eap)
  5812.     exarg_T    *eap;
  5813. {
  5814.     if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL)
  5815.     MSG(_("No swap file"));
  5816.     else
  5817.     msg(curbuf->b_ml.ml_mfp->mf_fname);
  5818. }
  5819.  
  5820. /*
  5821.  * ":syncbind" forces all 'scrollbind' windows to have the same relative
  5822.  * offset.
  5823.  * (1998-11-02 16:21:01  R. Edward Ralston <eralston@computer.org>)
  5824.  */
  5825. /*ARGSUSED*/
  5826.     static void
  5827. ex_syncbind(eap)
  5828.     exarg_T    *eap;
  5829. {
  5830. #ifdef FEAT_SCROLLBIND
  5831.     win_T    *wp;
  5832.     long    topline;
  5833.     long    y;
  5834.     linenr_T    old_linenr = curwin->w_cursor.lnum;
  5835.  
  5836.     setpcmark();
  5837.  
  5838.     /*
  5839.      * determine max topline
  5840.      */
  5841.     if (curwin->w_p_scb)
  5842.     {
  5843.     topline = curwin->w_topline;
  5844.     for (wp = firstwin; wp; wp = wp->w_next)
  5845.     {
  5846.         if (wp->w_p_scb && wp->w_buffer)
  5847.         {
  5848.         y = wp->w_buffer->b_ml.ml_line_count - p_so;
  5849.         if (topline > y)
  5850.             topline = y;
  5851.         }
  5852.     }
  5853.     if (topline < 1)
  5854.         topline = 1;
  5855.     }
  5856.     else
  5857.     {
  5858.     topline = 1;
  5859.     }
  5860.  
  5861.  
  5862.     /*
  5863.      * set all scrollbind windows to the same topline
  5864.      */
  5865.     wp = curwin;
  5866.     for (curwin = firstwin; curwin; curwin = curwin->w_next)
  5867.     {
  5868.     if (curwin->w_p_scb)
  5869.     {
  5870.         y = topline - curwin->w_topline;
  5871.         if (y > 0)
  5872.         scrollup(y, TRUE);
  5873.         else
  5874.         scrolldown(-y, TRUE);
  5875.         curwin->w_scbind_pos = topline;
  5876.         redraw_later(VALID);
  5877.         cursor_correct();
  5878. #ifdef FEAT_WINDOWS
  5879.         curwin->w_redr_status = TRUE;
  5880. #endif
  5881.     }
  5882.     }
  5883.     curwin = wp;
  5884.     if (curwin->w_p_scb)
  5885.     {
  5886.     did_syncbind = TRUE;
  5887.     checkpcmark();
  5888.     if (old_linenr != curwin->w_cursor.lnum)
  5889.     {
  5890.         char_u ctrl_o[2];
  5891.  
  5892.         ctrl_o[0] = Ctrl_O;
  5893.         ctrl_o[1] = 0;
  5894.         ins_typebuf(ctrl_o, REMAP_NONE, 0, TRUE, FALSE);
  5895.     }
  5896.     }
  5897. #endif
  5898. }
  5899.  
  5900.  
  5901.     static void
  5902. ex_read(eap)
  5903.     exarg_T    *eap;
  5904. {
  5905.     int        i;
  5906.  
  5907.     if (eap->usefilter)            /* :r!cmd */
  5908.     do_bang(1, eap, FALSE, FALSE, TRUE);
  5909.     else
  5910.     {
  5911.     if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL)
  5912.         return;
  5913.  
  5914. #ifdef FEAT_BROWSE
  5915.     if (cmdmod.browse)
  5916.     {
  5917.         char_u *browseFile;
  5918.  
  5919.         browseFile = do_browse(FALSE, (char_u *)_("Append File"), NULL,
  5920.                         NULL, eap->arg, NULL, curbuf);
  5921.         if (browseFile != NULL)
  5922.         {
  5923.         i = readfile(browseFile, NULL,
  5924.               eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
  5925.         vim_free(browseFile);
  5926.         }
  5927.         else
  5928.         i = OK;
  5929.     }
  5930.     else
  5931. #endif
  5932.          if (*eap->arg == NUL)
  5933.     {
  5934.         if (check_fname() == FAIL)    /* check for no file name */
  5935.         return;
  5936.         i = readfile(curbuf->b_ffname, curbuf->b_fname,
  5937.               eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
  5938.     }
  5939.     else
  5940.     {
  5941.         if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL)
  5942.         (void)setaltfname(eap->arg, eap->arg, (linenr_T)1);
  5943.         i = readfile(eap->arg, NULL,
  5944.               eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
  5945.  
  5946.     }
  5947.     if (i == FAIL)
  5948.         EMSG2(_(e_notopen), eap->arg);
  5949.     else
  5950.         redraw_curbuf_later(VALID);
  5951.     }
  5952. }
  5953.  
  5954. /*
  5955.  * ":cd", ":lcd", ":chdir" and ":lchdir".
  5956.  */
  5957.     static void
  5958. ex_cd(eap)
  5959.     exarg_T    *eap;
  5960. {
  5961.     static char_u    *prev_dir = NULL;
  5962.     char_u        *new_dir;
  5963.     char_u        *tofree;
  5964.  
  5965.     new_dir = eap->arg;
  5966. #if !defined(UNIX) && !defined(VMS)
  5967.     /* for non-UNIX ":cd" means: print current directory */
  5968.     if (*new_dir == NUL)
  5969.     ex_pwd(NULL);
  5970.     else
  5971. #endif
  5972.     {
  5973.     /* ":cd -": Change to previous directory */
  5974.     if (STRCMP(new_dir, "-") == 0)
  5975.     {
  5976.         if (prev_dir == NULL)
  5977.         {
  5978.         EMSG(_("E186: No previous directory"));
  5979.         return;
  5980.         }
  5981.         new_dir = prev_dir;
  5982.     }
  5983.  
  5984.     /* Save current directory for next ":cd -" */
  5985.     tofree = prev_dir;
  5986.     if (mch_dirname(NameBuff, MAXPATHL) == OK)
  5987.         prev_dir = vim_strsave(NameBuff);
  5988.     else
  5989.         prev_dir = NULL;
  5990.  
  5991. #if defined(UNIX) || defined(VMS)
  5992.     /* for UNIX ":cd" means: go to home directory */
  5993.     if (*new_dir == NUL)
  5994.     {
  5995.         /* use NameBuff for home directory name */
  5996. # ifdef VMS
  5997.         char_u    *p;
  5998.  
  5999.         p = mch_getenv((char_u *)"SYS$LOGIN");
  6000.         if (p == NULL || *p == NUL)    /* empty is the same as not set */
  6001.         NameBuff[0] = NUL;
  6002.         else
  6003.         STRNCPY(NameBuff, p, MAXPATHL);
  6004. # else
  6005.         expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
  6006. # endif
  6007.         new_dir = NameBuff;
  6008.     }
  6009. #endif
  6010.     if (new_dir == NULL || vim_chdir(new_dir))
  6011.         EMSG(_(e_failed));
  6012.     else
  6013.     {
  6014.         vim_free(curwin->w_localdir);
  6015.         if (eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir)
  6016.         {
  6017.         /* If still in global directory, need to remember current
  6018.          * directory as global directory. */
  6019.         if (globaldir == NULL && prev_dir != NULL)
  6020.             globaldir = vim_strsave(prev_dir);
  6021.         /* Remember this local directory for the window. */
  6022.         if (mch_dirname(NameBuff, MAXPATHL) == OK)
  6023.             curwin->w_localdir = vim_strsave(NameBuff);
  6024.         }
  6025.         else
  6026.         {
  6027.         /* We are now in the global directory, no need to remember its
  6028.          * name. */
  6029.         vim_free(globaldir);
  6030.         globaldir = NULL;
  6031.         curwin->w_localdir = NULL;
  6032.         }
  6033.  
  6034.         shorten_fnames(TRUE);
  6035.  
  6036.         /* Echo the new current directory if the command was typed. */
  6037.         if (KeyTyped)
  6038.         ex_pwd(eap);
  6039.     }
  6040.     vim_free(tofree);
  6041.     }
  6042. }
  6043.  
  6044. /*
  6045.  * ":pwd".
  6046.  */
  6047. /*ARGSUSED*/
  6048.     static void
  6049. ex_pwd(eap)
  6050.     exarg_T    *eap;
  6051. {
  6052.     if (mch_dirname(NameBuff, MAXPATHL) == OK)
  6053.     msg(NameBuff);
  6054.     else
  6055.     EMSG(_("E187: Unknown"));
  6056. }
  6057.  
  6058. /*
  6059.  * ":=".
  6060.  */
  6061.     static void
  6062. ex_equal(eap)
  6063.     exarg_T    *eap;
  6064. {
  6065.     smsg((char_u *)_("line %ld"), (long)eap->line2);
  6066. }
  6067.  
  6068.     static void
  6069. ex_sleep(eap)
  6070.     exarg_T    *eap;
  6071. {
  6072.     int        n;
  6073.  
  6074.     if (cursor_valid())
  6075.     {
  6076.     n = W_WINROW(curwin) + curwin->w_wrow - msg_scrolled;
  6077.     if (n >= 0)
  6078.         windgoto((int)n, curwin->w_wcol);
  6079.     }
  6080.     do_sleep(eap->line2 * (*eap->arg == 'm' ? 1L : 1000L));
  6081. }
  6082.  
  6083. /*
  6084.  * Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second.
  6085.  */
  6086.     void
  6087. do_sleep(msec)
  6088.     long    msec;
  6089. {
  6090.     long    done;
  6091.  
  6092.     cursor_on();
  6093.     out_flush();
  6094.     for (done = 0; !got_int && done < msec; done += 1000L)
  6095.     {
  6096.     ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE);
  6097.     ui_breakcheck();
  6098.     }
  6099. }
  6100.  
  6101.     static void
  6102. do_exmap(eap, isabbrev)
  6103.     exarg_T    *eap;
  6104.     int        isabbrev;
  6105. {
  6106.     int        mode;
  6107.     char_u  *cmdp;
  6108.  
  6109.     cmdp = eap->cmd;
  6110.     mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
  6111.  
  6112.     switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
  6113.                             eap->arg, mode, isabbrev))
  6114.     {
  6115.     case 1: EMSG(_(e_invarg));
  6116.         break;
  6117.     case 2: EMSG(isabbrev ? _(e_noabbr) : _(e_nomap));
  6118.         break;
  6119.     }
  6120. }
  6121.  
  6122. /*
  6123.  * ":winsize" command (obsolete).
  6124.  */
  6125.     static void
  6126. ex_winsize(eap)
  6127.     exarg_T    *eap;
  6128. {
  6129.     int        w, h;
  6130.     char_u    *arg = eap->arg;
  6131.  
  6132.     w = getdigits(&arg);
  6133.     arg = skipwhite(arg);
  6134.     h = getdigits(&arg);
  6135.     set_shellsize(w, h, TRUE);
  6136. }
  6137.  
  6138. #ifdef FEAT_WINDOWS
  6139.     static void
  6140. ex_wincmd(eap)
  6141.     exarg_T    *eap;
  6142. {
  6143.     if (*eap->arg == 'g' || *eap->arg == Ctrl_G)
  6144.     {
  6145.     /* CTRL-W g and CTRL-W CTRL-G  have an extra command character */
  6146.     if (eap->arg[1] == NUL)
  6147.     {
  6148.         EMSG(_(e_invarg));
  6149.         return;
  6150.     }
  6151.     stuffcharReadbuff(eap->arg[1]);
  6152.     }
  6153.     do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L);
  6154. }
  6155. #endif
  6156.  
  6157. #if defined(FEAT_GUI) || defined(UNIX) || defined(VMS)
  6158. /*
  6159.  * ":winpos".
  6160.  */
  6161.     static void
  6162. ex_winpos(eap)
  6163.     exarg_T    *eap;
  6164. {
  6165.     int        x, y;
  6166.     char_u    *arg = eap->arg;
  6167.  
  6168.     if (*arg == NUL)
  6169.     {
  6170. # ifdef FEAT_GUI
  6171.     if (gui.in_use && gui_mch_get_winpos(&x, &y) != FAIL)
  6172.     {
  6173.         sprintf((char *)IObuff, _("Window position: X %d, Y %d"), x, y);
  6174.         msg(IObuff);
  6175.     }
  6176.     else
  6177. # endif
  6178.         EMSG(_("E188: Obtaining window position not implemented for this platform"));
  6179.     }
  6180.     else
  6181.     {
  6182.     x = getdigits(&arg);
  6183.     arg = skipwhite(arg);
  6184.     y = getdigits(&arg);
  6185. # ifdef FEAT_GUI
  6186.     if (gui.in_use)
  6187.         gui_mch_set_winpos(x, y);
  6188.     else if (gui.starting)
  6189.     {
  6190.         /* Remember the coordinates for when the window is opened. */
  6191.         gui_win_x = x;
  6192.         gui_win_y = y;
  6193.     }
  6194. #  ifdef HAVE_TGETENT
  6195.     else
  6196. #  endif
  6197. # endif
  6198. # ifdef HAVE_TGETENT
  6199.     if (*T_CWP)
  6200.         term_set_winpos(x, y);
  6201. # endif
  6202.     }
  6203. }
  6204. #endif
  6205.  
  6206. /*
  6207.  * Handle command that work like operators: ":delete", ":yank", ":>" and ":<".
  6208.  */
  6209.     static void
  6210. ex_operators(eap)
  6211.     exarg_T    *eap;
  6212. {
  6213.     oparg_T    oa;
  6214.  
  6215.     clear_oparg(&oa);
  6216.     oa.regname = eap->regname;
  6217.     oa.start.lnum = eap->line1;
  6218.     oa.end.lnum = eap->line2;
  6219.     oa.line_count = eap->line2 - eap->line1 + 1;
  6220.     oa.motion_type = MLINE;
  6221.     if (eap->cmdidx != CMD_yank)    /* position cursor for undo */
  6222.     {
  6223.     setpcmark();
  6224.     curwin->w_cursor.lnum = eap->line1;
  6225.     beginline(BL_SOL | BL_FIX);
  6226.     }
  6227.  
  6228.     switch (eap->cmdidx)
  6229.     {
  6230.     case CMD_delete:
  6231.         oa.op_type = OP_DELETE;
  6232.         op_delete(&oa);
  6233.         break;
  6234.  
  6235.     case CMD_yank:
  6236.         oa.op_type = OP_YANK;
  6237.         (void)op_yank(&oa, FALSE, TRUE);
  6238.         break;
  6239.  
  6240.     default:    /* CMD_rshift or CMD_lshift */
  6241.         if ((eap->cmdidx == CMD_rshift)
  6242. #ifdef FEAT_RIGHTLEFT
  6243.                     ^ curwin->w_p_rl
  6244. #endif
  6245.                             )
  6246.         oa.op_type = OP_RSHIFT;
  6247.         else
  6248.         oa.op_type = OP_LSHIFT;
  6249.         op_shift(&oa, FALSE, eap->amount);
  6250.         break;
  6251.     }
  6252. }
  6253.  
  6254. /*
  6255.  * ":put".
  6256.  */
  6257.     static void
  6258. ex_put(eap)
  6259.     exarg_T    *eap;
  6260. {
  6261.     /* ":0put" works like ":1put!". */
  6262.     if (eap->line2 == 0)
  6263.     {
  6264.     eap->line2 = 1;
  6265.     eap->forceit = TRUE;
  6266.     }
  6267.     curwin->w_cursor.lnum = eap->line2;
  6268.     do_put(eap->regname, eap->forceit ? BACKWARD : FORWARD, -1L, 0);
  6269. }
  6270.  
  6271. /*
  6272.  * Handle ":copy" and ":move".
  6273.  */
  6274.     static void
  6275. ex_copymove(eap)
  6276.     exarg_T    *eap;
  6277. {
  6278.     long    n;
  6279.  
  6280.     n = get_address(&eap->arg, FALSE);
  6281.     if (eap->arg == NULL)        /* error detected */
  6282.     {
  6283.     eap->nextcmd = NULL;
  6284.     return;
  6285.     }
  6286.  
  6287.     /*
  6288.      * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n'
  6289.      */
  6290.     if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
  6291.     {
  6292.     EMSG(_(e_invaddr));
  6293.     return;
  6294.     }
  6295.  
  6296.     if (eap->cmdidx == CMD_move)
  6297.     {
  6298.     if (do_move(eap->line1, eap->line2, n) == FAIL)
  6299.         return;
  6300.     }
  6301.     else
  6302.     ex_copy(eap->line1, eap->line2, n);
  6303.     u_clearline();
  6304.     beginline(BL_SOL | BL_FIX);
  6305. }
  6306.  
  6307. /*
  6308.  * ":smagic" and ":snomagic".
  6309.  */
  6310.     static void
  6311. ex_submagic(eap)
  6312.     exarg_T    *eap;
  6313. {
  6314.     int        magic_save = p_magic;
  6315.  
  6316.     p_magic = (eap->cmdidx == CMD_smagic);
  6317.     do_sub(eap);
  6318.     p_magic = magic_save;
  6319. }
  6320.  
  6321. /*
  6322.  * ":join".
  6323.  */
  6324.     static void
  6325. ex_join(eap)
  6326.     exarg_T    *eap;
  6327. {
  6328.     curwin->w_cursor.lnum = eap->line1;
  6329.     if (eap->line1 == eap->line2)
  6330.     {
  6331.     if (eap->addr_count >= 2)   /* :2,2join does nothing */
  6332.         return;
  6333.     if (eap->line2 == curbuf->b_ml.ml_line_count)
  6334.     {
  6335.         beep_flush();
  6336.         return;
  6337.     }
  6338.     ++eap->line2;
  6339.     }
  6340.     do_do_join(eap->line2 - eap->line1 + 1, !eap->forceit);
  6341.     beginline(BL_WHITE | BL_FIX);
  6342. }
  6343.  
  6344. /*
  6345.  * ":[addr]@r" or ":[addr]*r": execute register
  6346.  */
  6347.     static void
  6348. ex_at(eap)
  6349.     exarg_T    *eap;
  6350. {
  6351.     int        c;
  6352.  
  6353.     curwin->w_cursor.lnum = eap->line2;
  6354.  
  6355. #ifdef USE_ON_FLY_SCROLL
  6356.     dont_scroll = TRUE;        /* disallow scrolling here */
  6357. #endif
  6358.  
  6359.     /* get the register name.  No name means to use the previous one */
  6360.     c = *eap->arg;
  6361.     if (c == NUL || (c == '*' && *eap->cmd == '*'))
  6362.     c = '@';
  6363.     /* put the register in mapbuf */
  6364.     if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL) == FAIL)
  6365.     beep_flush();
  6366.     else
  6367.     {
  6368.     int    save_efr = exec_from_reg;
  6369.  
  6370.     exec_from_reg = TRUE;
  6371.     /* execute from the mapbuf */
  6372.     while (vpeekc() == ':')
  6373.         (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
  6374.  
  6375.     exec_from_reg = save_efr;
  6376.     }
  6377. }
  6378.  
  6379. /*
  6380.  * ":!".
  6381.  */
  6382.     static void
  6383. ex_bang(eap)
  6384.     exarg_T    *eap;
  6385. {
  6386.     do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE);
  6387. }
  6388.  
  6389. /*
  6390.  * ":undo".
  6391.  */
  6392. /*ARGSUSED*/
  6393.     static void
  6394. ex_undo(eap)
  6395.     exarg_T    *eap;
  6396. {
  6397.     u_undo(1);
  6398. }
  6399.  
  6400. /*
  6401.  * ":redo".
  6402.  */
  6403. /*ARGSUSED*/
  6404.     static void
  6405. ex_redo(eap)
  6406.     exarg_T    *eap;
  6407. {
  6408.     u_redo(1);
  6409. }
  6410.  
  6411. /*
  6412.  * ":redir": start/stop redirection.
  6413.  */
  6414.     static void
  6415. ex_redir(eap)
  6416.     exarg_T    *eap;
  6417. {
  6418.     char    *mode;
  6419. #ifdef FEAT_BROWSE
  6420.     char_u    *browseFile = NULL;
  6421. #endif
  6422.  
  6423.     if (STRICMP(eap->arg, "END") == 0)
  6424.     close_redir();
  6425.     else
  6426.     {
  6427.     if (*eap->arg == '>')
  6428.     {
  6429.         ++eap->arg;
  6430.         if (*eap->arg == '>')
  6431.         {
  6432.         ++eap->arg;
  6433.         mode = "a";
  6434.         }
  6435.         else
  6436.         mode = "w";
  6437.         eap->arg = skipwhite(eap->arg);
  6438.  
  6439.         close_redir();
  6440.  
  6441. #ifdef FEAT_BROWSE
  6442.         if (cmdmod.browse)
  6443.         {
  6444.         browseFile = do_browse(TRUE, (char_u *)_("Save Redirection"),
  6445.                NULL, NULL, eap->arg, BROWSE_FILTER_ALL_FILES, curbuf);
  6446.         if (browseFile == NULL)
  6447.             return;        /* operation cancelled */
  6448.         eap->arg = browseFile;
  6449.         eap->forceit = TRUE;    /* since dialog already asked */
  6450.         }
  6451. #endif
  6452.  
  6453.         redir_fd = open_exfile(eap->arg, eap->forceit, mode);
  6454.  
  6455. #ifdef FEAT_BROWSE
  6456.         vim_free(browseFile);
  6457. #endif
  6458.     }
  6459. #ifdef FEAT_EVAL
  6460.     else if (*eap->arg == '@')
  6461.     {
  6462.         /* redirect to a register a-z (resp. A-Z for appending) */
  6463.         close_redir();
  6464.         ++eap->arg;
  6465.         if (ASCII_ISALPHA(*eap->arg)
  6466. # ifdef FEAT_CLIPBOARD
  6467.             || *eap->arg == '*'
  6468. # endif
  6469.             || *eap->arg == '"')
  6470.         {
  6471.         redir_reg = *eap->arg;
  6472.         if (islower(redir_reg)
  6473. # ifdef FEAT_CLIPBOARD
  6474.             || redir_reg == '*'
  6475. # endif
  6476.             || redir_reg == '"')
  6477.         {
  6478.             /* make register empty */
  6479.             write_reg_contents(redir_reg, (char_u *)"", FALSE);
  6480.         }
  6481.         }
  6482.         else
  6483.         EMSG(_(e_invarg));
  6484.     }
  6485. #endif
  6486.  
  6487.     /* TODO: redirect to a buffer */
  6488.  
  6489.     /* TODO: redirect to an internal variable */
  6490.  
  6491.     else
  6492.         EMSG(_(e_invarg));
  6493.     }
  6494. }
  6495.  
  6496. /*
  6497.  * ":redraw": force redraw
  6498.  */
  6499.     static void
  6500. ex_redraw(eap)
  6501.     exarg_T    *eap;
  6502. {
  6503.     int        r = RedrawingDisabled;
  6504.     int        p = p_lz;
  6505.  
  6506.     RedrawingDisabled = 0;
  6507.     p_lz = FALSE;
  6508.     update_screen(eap->forceit ? CLEAR : 0);
  6509.     RedrawingDisabled = r;
  6510.     p_lz = p;
  6511.     out_flush();
  6512. }
  6513.  
  6514.     static void
  6515. close_redir()
  6516. {
  6517.     if (redir_fd != NULL)
  6518.     {
  6519.     fclose(redir_fd);
  6520.     redir_fd = NULL;
  6521.     }
  6522. #ifdef FEAT_EVAL
  6523.     redir_reg = 0;
  6524. #endif
  6525. }
  6526.  
  6527. #if defined(FEAT_SESSION) && defined(USE_CRNL)
  6528. # define MKSESSION_NL
  6529. static int mksession_nl = FALSE;    /* use NL only in put_eol() */
  6530. #endif
  6531.  
  6532. /*
  6533.  * ":mkexrc", ":mkvimrc", ":mkview" and ":mksession".
  6534.  */
  6535.     static void
  6536. ex_mkrc(eap)
  6537.     exarg_T    *eap;
  6538. {
  6539.     FILE    *fd;
  6540.     int        failed = FALSE;
  6541.     char_u    *fname;
  6542. #ifdef FEAT_BROWSE
  6543.     char_u    *browseFile = NULL;
  6544. #endif
  6545. #ifdef FEAT_SESSION
  6546.     int        view_session = FALSE;
  6547.     int        using_vdir = FALSE;    /* using 'viewdir'? */
  6548.     char_u    *viewFile = NULL;
  6549.     unsigned    *flagp;
  6550. #endif
  6551.  
  6552.     if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview)
  6553.     {
  6554. #ifdef FEAT_SESSION
  6555.     view_session = TRUE;
  6556. #else
  6557.     ex_ni(eap);
  6558.     return;
  6559. #endif
  6560.     }
  6561.  
  6562. #ifdef FEAT_SESSION
  6563.     /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */
  6564.     if (eap->cmdidx == CMD_mkview
  6565.         && (*eap->arg == NUL
  6566.         || (isdigit(*eap->arg) && eap->arg[1] == NUL)))
  6567.     {
  6568.     eap->forceit = TRUE;
  6569.     fname = get_view_file(*eap->arg);
  6570.     if (fname == NULL)
  6571.         return;
  6572.     viewFile = fname;
  6573.     using_vdir = TRUE;
  6574.     }
  6575.     else
  6576. #endif
  6577.     if (*eap->arg != NUL)
  6578.     fname = eap->arg;
  6579.     else if (eap->cmdidx == CMD_mkvimrc)
  6580.     fname = (char_u *)VIMRC_FILE;
  6581. #ifdef FEAT_SESSION
  6582.     else if (eap->cmdidx == CMD_mksession)
  6583.     fname = (char_u *)SESSION_FILE;
  6584. #endif
  6585.     else
  6586.     fname = (char_u *)EXRC_FILE;
  6587.  
  6588. #ifdef FEAT_BROWSE
  6589.     if (cmdmod.browse)
  6590.     {
  6591.     browseFile = do_browse(TRUE,
  6592. # ifdef FEAT_SESSION
  6593.         eap->cmdidx == CMD_mkview ? (char_u *)_("Save View") :
  6594.         eap->cmdidx == CMD_mksession ? (char_u *)_("Save Session") :
  6595. # endif
  6596.         (char_u *)_("Save Setup"),
  6597.         NULL, (char_u *)"vim", fname, BROWSE_FILTER_MACROS, curbuf);
  6598.     if (browseFile == NULL)
  6599.         goto theend;
  6600.     fname = browseFile;
  6601.     eap->forceit = TRUE;    /* since dialog already asked */
  6602.     }
  6603. #endif
  6604.  
  6605. #if defined(FEAT_SESSION) && defined(vim_mkdir)
  6606.     /* When using 'viewdir' may have to create the directory. */
  6607.     if (using_vdir && !mch_isdir(p_vdir))
  6608.     vim_mkdir(p_vdir, 0755); /* ignore errors, open_exfile() will fail */
  6609. #endif
  6610.  
  6611.     fd = open_exfile(fname, eap->forceit, WRITEBIN);
  6612.     if (fd != NULL)
  6613.     {
  6614. #ifdef FEAT_SESSION
  6615.     if (eap->cmdidx == CMD_mkview)
  6616.         flagp = &vop_flags;
  6617.     else
  6618.         flagp = &ssop_flags;
  6619. #endif
  6620.  
  6621. #ifdef MKSESSION_NL
  6622.     /* "unix" in 'sessionoptions': use NL line separator */
  6623.     if (view_session && (*flagp & SSOP_UNIX))
  6624.         mksession_nl = TRUE;
  6625. #endif
  6626.  
  6627.     /* Write the version command for :mkvimrc */
  6628.     if (eap->cmdidx == CMD_mkvimrc)
  6629.         (void)put_line(fd, "version 6.0");
  6630.  
  6631. #ifdef FEAT_SESSION
  6632.     if (eap->cmdidx != CMD_mkview)
  6633. #endif
  6634.     {
  6635.         /* Write setting 'compatible' first, because it has side effects */
  6636.         if (p_cp)
  6637.         (void)put_line(fd, "set compatible");
  6638.         else
  6639.         (void)put_line(fd, "set nocompatible");
  6640.     }
  6641.  
  6642. #ifdef FEAT_SESSION
  6643.     if (!view_session
  6644.         || (eap->cmdidx == CMD_mksession
  6645.             && (*flagp & SSOP_OPTIONS)))
  6646. #endif
  6647.         failed |= (makemap(fd, NULL) == FAIL
  6648.                    || makeset(fd, OPT_GLOBAL, FALSE) == FAIL);
  6649.  
  6650. #ifdef FEAT_SESSION
  6651.     if (!failed && view_session)
  6652.     {
  6653.         if (put_line(fd, "let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0") == FAIL)
  6654.         failed = TRUE;
  6655.         if (eap->cmdidx == CMD_mksession)
  6656.         {
  6657.         char_u dirnow[MAXPATHL];    /* current directory */
  6658.  
  6659.         /*
  6660.          * Change to session file's dir.
  6661.          */
  6662.         if (mch_dirname(dirnow, MAXPATHL) == FAIL)
  6663.             *dirnow = NUL;
  6664.         if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR))
  6665.         {
  6666.             if (vim_chdirfile(fname) == OK)
  6667.             shorten_fnames(TRUE);
  6668.         }
  6669.         else if (*dirnow != NUL
  6670.             && (ssop_flags & SSOP_CURDIR) && globaldir != NULL)
  6671.         {
  6672.             (void)mch_chdir((char *)globaldir);
  6673.             shorten_fnames(TRUE);
  6674.         }
  6675.  
  6676.         failed |= (makeopens(fd, dirnow) == FAIL);
  6677.  
  6678.         /* restore original dir */
  6679.         if (*dirnow != NUL && ((ssop_flags & SSOP_SESDIR)
  6680.             || ((ssop_flags & SSOP_CURDIR) && globaldir != NULL)))
  6681.         {
  6682.             (void)mch_chdir((char *)dirnow);
  6683.             shorten_fnames(TRUE);
  6684.         }
  6685.         }
  6686.         else
  6687.         {
  6688.         failed |= (put_view(fd, curwin, !using_vdir, flagp) == FAIL);
  6689.         }
  6690.         if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save")
  6691.                                       == FAIL)
  6692.         failed = TRUE;
  6693.     }
  6694. #endif
  6695.     failed |= fclose(fd);
  6696.  
  6697.     if (failed)
  6698.         EMSG(_(e_write));
  6699. #if defined(FEAT_EVAL) && defined(FEAT_SESSION)
  6700.     else if (eap->cmdidx == CMD_mksession)
  6701.     {
  6702.         /* successful session write - set this_session var */
  6703.         char_u    tbuf[MAXPATHL];
  6704.  
  6705.         if (vim_FullName(fname, tbuf, MAXPATHL, FALSE) == OK)
  6706.         set_vim_var_string(VV_THIS_SESSION, tbuf, -1);
  6707.     }
  6708. #endif
  6709. #ifdef MKSESSION_NL
  6710.     mksession_nl = FALSE;
  6711. #endif
  6712.     }
  6713.  
  6714. #ifdef FEAT_BROWSE
  6715. theend:
  6716.     vim_free(browseFile);
  6717. #endif
  6718. #ifdef FEAT_SESSION
  6719.     vim_free(viewFile);
  6720. #endif
  6721. }
  6722.  
  6723. /*
  6724.  * Open a file for writing for an Ex command, with some checks.
  6725.  * Return file descriptor, or NULL on failure.
  6726.  */
  6727.     FILE *
  6728. open_exfile(fname, forceit, mode)
  6729.     char_u    *fname;
  6730.     int        forceit;
  6731.     char    *mode;        /* "w" for create new file or "a" for append */
  6732. {
  6733.     FILE    *fd;
  6734.  
  6735. #ifdef UNIX
  6736.     /* with Unix it is possible to open a directory */
  6737.     if (mch_isdir(fname))
  6738.     {
  6739.     EMSG2(_(e_isadir2), fname);
  6740.     return NULL;
  6741.     }
  6742. #endif
  6743.     if (!forceit && *mode != 'a' && vim_fexists(fname))
  6744.     {
  6745.     EMSG2(_("E189: \"%s\" exists (use ! to override)"), fname);
  6746.     return NULL;
  6747.     }
  6748.  
  6749.     if ((fd = mch_fopen((char *)fname, mode)) == NULL)
  6750.     EMSG2(_("E190: Cannot open \"%s\" for writing"), fname);
  6751.  
  6752.     return fd;
  6753. }
  6754.  
  6755. /*
  6756.  * ":mark" and ":k".
  6757.  */
  6758.     static void
  6759. ex_mark(eap)
  6760.     exarg_T    *eap;
  6761. {
  6762.     pos_T    pos;
  6763.  
  6764.     if (*eap->arg == NUL)        /* No argument? */
  6765.     EMSG(_(e_argreq));
  6766.     else if (eap->arg[1] != NUL)    /* more than one character? */
  6767.     EMSG(_(e_trailing));
  6768.     else
  6769.     {
  6770.     pos = curwin->w_cursor;        /* save curwin->w_cursor */
  6771.     curwin->w_cursor.lnum = eap->line2;
  6772.     beginline(BL_WHITE | BL_FIX);
  6773.     if (setmark(*eap->arg) == FAIL)    /* set mark */
  6774.         EMSG(_("E191: Argument must be a letter or forward/backward quote"));
  6775.     curwin->w_cursor = pos;        /* restore curwin->w_cursor */
  6776.     }
  6777. }
  6778.  
  6779. #ifdef FEAT_EX_EXTRA
  6780. /*
  6781.  * ":normal[!] {commands}": Execute normal mode commands.
  6782.  */
  6783.     static void
  6784. ex_normal(eap)
  6785.     exarg_T    *eap;
  6786. {
  6787.     oparg_T    oa;
  6788.     int        save_msg_scroll = msg_scroll;
  6789.     int        save_restart_edit = restart_edit;
  6790.     int        save_msg_didout = msg_didout;
  6791.     int        save_State = State;
  6792.     typebuf_T    saved_typebuf;
  6793.     int        save_insertmode = p_im;
  6794.     int        save_finish_op = finish_op;
  6795. #ifdef FEAT_MBYTE
  6796.     char_u    *arg = NULL;
  6797.     int        l;
  6798.     char_u    *p;
  6799. #endif
  6800.  
  6801.     if (ex_normal_busy >= p_mmd)
  6802.     {
  6803.     EMSG(_("E192: Recursive use of :normal too deep"));
  6804.     return;
  6805.     }
  6806.     ++ex_normal_busy;
  6807.  
  6808.     msg_scroll = FALSE;        /* no msg scrolling in Normal mode */
  6809.     restart_edit = 0;        /* don't go to Insert mode */
  6810.     p_im = FALSE;        /* don't use 'insertmode' */
  6811.  
  6812. #ifdef FEAT_MBYTE
  6813.     /*
  6814.      * vgetc() expects a CSI and K_SPECIAL to have been escaped.  Don't do
  6815.      * this for the K_SPECIAL leading byte, otherwise special keys will not
  6816.      * work.
  6817.      */
  6818.     if (has_mbyte)
  6819.     {
  6820.     int    len = 0;
  6821.  
  6822.     /* Count the number of characters to be escaped. */
  6823.     for (p = eap->arg; *p != NUL; ++p)
  6824.     {
  6825. # ifdef FEAT_GUI
  6826.         if (*p == CSI)  /* leadbyte CSI */
  6827.         len += 2;
  6828. # endif
  6829.         for (l = (*mb_ptr2len_check)(p) - 1; l > 0; --l)
  6830.         if (*++p == K_SPECIAL      /* trailbyte K_SPECIAL or CSI */
  6831. # ifdef FEAT_GUI
  6832.             || *p == CSI
  6833. # endif
  6834.             )
  6835.             len += 2;
  6836.     }
  6837.     if (len > 0)
  6838.     {
  6839.         arg = alloc((unsigned)(STRLEN(eap->arg) + len + 1));
  6840.         if (arg != NULL)
  6841.         {
  6842.         len = 0;
  6843.         for (p = eap->arg; *p != NUL; ++p)
  6844.         {
  6845.             arg[len++] = *p;
  6846. # ifdef FEAT_GUI
  6847.             if (*p == CSI)
  6848.             {
  6849.             arg[len++] = KS_EXTRA;
  6850.             arg[len++] = (int)KE_CSI;
  6851.             }
  6852. # endif
  6853.             for (l = (*mb_ptr2len_check)(p) - 1; l > 0; --l)
  6854.             {
  6855.             arg[len++] = *++p;
  6856.             if (*p == K_SPECIAL)
  6857.             {
  6858.                 arg[len++] = KS_SPECIAL;
  6859.                 arg[len++] = KE_FILLER;
  6860.             }
  6861. # ifdef FEAT_GUI
  6862.             else if (*p == CSI)
  6863.             {
  6864.                 arg[len++] = KS_EXTRA;
  6865.                 arg[len++] = (int)KE_CSI;
  6866.             }
  6867. # endif
  6868.             }
  6869.             arg[len] = NUL;
  6870.         }
  6871.         }
  6872.     }
  6873.     }
  6874. #endif
  6875.  
  6876.     /*
  6877.      * Save the current typeahead.  This is required to allow using ":normal"
  6878.      * from an event handler and makes sure we don't hang when the argument
  6879.      * ends with half a command.
  6880.      */
  6881.     saved_typebuf = typebuf;
  6882.     if (alloc_typebuf() == OK)
  6883.     {
  6884.     /*
  6885.      * Repeat the :normal command for each line in the range.  When no
  6886.      * range given, execute it just once, without positioning the cursor
  6887.      * first.
  6888.      */
  6889.     do
  6890.     {
  6891.         clear_oparg(&oa);
  6892.         finish_op = FALSE;
  6893.         if (eap->addr_count != 0)
  6894.         {
  6895.         curwin->w_cursor.lnum = eap->line1++;
  6896.         curwin->w_cursor.col = 0;
  6897.         }
  6898.  
  6899.         /*
  6900.          * Stuff the argument into the typeahead buffer.
  6901.          * Execute normal_cmd() until there is no typeahead left.
  6902.          */
  6903.         ins_typebuf(
  6904. #ifdef FEAT_MBYTE
  6905.             arg != NULL ? arg :
  6906. #endif
  6907.             eap->arg, eap->forceit ? REMAP_NONE : REMAP_YES, 0,
  6908.                                  TRUE, FALSE);
  6909.         while ((!stuff_empty() || (!typebuf_typed() && typebuf.tb_len > 0))
  6910.             && !got_int)
  6911.         {
  6912.         update_topline_cursor();
  6913.         normal_cmd(&oa, FALSE);    /* execute a Normal mode cmd */
  6914.         }
  6915.     }
  6916.     while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int);
  6917.     }
  6918.  
  6919.     /* Might not return to the main loop when in an event handler. */
  6920.     update_topline_cursor();
  6921.  
  6922.     /* Restore the previous typeahead. */
  6923.     free_typebuf();
  6924.     typebuf = saved_typebuf;
  6925.  
  6926.     --ex_normal_busy;
  6927.     msg_scroll = save_msg_scroll;
  6928.     restart_edit = save_restart_edit;
  6929.     p_im = save_insertmode;
  6930.     finish_op = save_finish_op;
  6931.     msg_didout |= save_msg_didout;    /* don't reset msg_didout now */
  6932.  
  6933.     /* Restore the state (needed when called from a function executed for
  6934.      * 'indentexpr'). */
  6935.     State = save_State;
  6936. #ifdef FEAT_MBYTE
  6937.     vim_free(arg);
  6938. #endif
  6939. }
  6940.  
  6941. /*
  6942.  * Update w_topline, w_leftcol and the cursor position.
  6943.  */
  6944.     static void
  6945. update_topline_cursor()
  6946. {
  6947.     check_cursor();        /* put cursor on valid line */
  6948.     update_topline();
  6949.     if (!curwin->w_p_wrap)
  6950.     validate_cursor();
  6951.     update_curswant();
  6952. }
  6953.  
  6954. /*
  6955.  * ":startinsert"
  6956.  */
  6957.     static void
  6958. ex_startinsert(eap)
  6959.     exarg_T    *eap;
  6960. {
  6961.     if (eap->forceit)
  6962.     {
  6963.     coladvance((colnr_T)MAXCOL);
  6964.     curwin->w_curswant = MAXCOL;
  6965.     curwin->w_set_curswant = FALSE;
  6966.     restart_edit = 'a';
  6967.     }
  6968.     else
  6969.     restart_edit = 'i';
  6970. }
  6971. #endif
  6972.  
  6973. #ifdef FEAT_FIND_ID
  6974.     static void
  6975. ex_checkpath(eap)
  6976.     exarg_T    *eap;
  6977. {
  6978.     find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L,
  6979.                    eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
  6980.                           (linenr_T)1, (linenr_T)MAXLNUM);
  6981. }
  6982.  
  6983. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  6984. /*
  6985.  * ":psearch"
  6986.  */
  6987.     static void
  6988. ex_psearch(eap)
  6989.     exarg_T    *eap;
  6990. {
  6991.     g_do_tagpreview = p_pvh;
  6992.     ex_findpat(eap);
  6993.     g_do_tagpreview = 0;
  6994. }
  6995. #endif
  6996.  
  6997.     static void
  6998. ex_findpat(eap)
  6999.     exarg_T    *eap;
  7000. {
  7001.     int        whole = TRUE;
  7002.     long    n;
  7003.     char_u    *p;
  7004.     int        action;
  7005.  
  7006.     switch (cmdnames[eap->cmdidx].cmd_name[2])
  7007.     {
  7008.     case 'e':    /* ":psearch", ":isearch" and ":dsearch" */
  7009.         if (cmdnames[eap->cmdidx].cmd_name[0] == 'p')
  7010.             action = ACTION_GOTO;
  7011.         else
  7012.             action = ACTION_SHOW;
  7013.         break;
  7014.     case 'i':    /* ":ilist" and ":dlist" */
  7015.         action = ACTION_SHOW_ALL;
  7016.         break;
  7017.     case 'u':    /* ":ijump" and ":djump" */
  7018.         action = ACTION_GOTO;
  7019.         break;
  7020.     default:    /* ":isplit" and ":dsplit" */
  7021.         action = ACTION_SPLIT;
  7022.         break;
  7023.     }
  7024.  
  7025.     n = 1;
  7026.     if (isdigit(*eap->arg))    /* get count */
  7027.     {
  7028.     n = getdigits(&eap->arg);
  7029.     eap->arg = skipwhite(eap->arg);
  7030.     }
  7031.     if (*eap->arg == '/')   /* Match regexp, not just whole words */
  7032.     {
  7033.     whole = FALSE;
  7034.     ++eap->arg;
  7035.     p = skip_regexp(eap->arg, '/', p_magic);
  7036.     if (*p)
  7037.     {
  7038.         *p++ = NUL;
  7039.         p = skipwhite(p);
  7040.  
  7041.         /* Check for trailing illegal characters */
  7042.         if (!ends_excmd(*p))
  7043.         eap->errmsg = e_trailing;
  7044.         else
  7045.         eap->nextcmd = check_nextcmd(p);
  7046.     }
  7047.     }
  7048.     if (!eap->skip)
  7049.     find_pattern_in_path(eap->arg, 0, (int)STRLEN(eap->arg),
  7050.                 whole, !eap->forceit,
  7051.                 *eap->cmd == 'd' ?    FIND_DEFINE : FIND_ANY,
  7052.                 n, action, eap->line1, eap->line2);
  7053. }
  7054. #endif
  7055.  
  7056. #ifdef FEAT_WINDOWS
  7057.  
  7058. # ifdef FEAT_QUICKFIX
  7059. /*
  7060.  * ":ptag", ":ptselect", ":ptjump", ":ptnext", etc.
  7061.  */
  7062.     static void
  7063. ex_ptag(eap)
  7064.     exarg_T    *eap;
  7065. {
  7066.     g_do_tagpreview = p_pvh;
  7067.     ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
  7068. }
  7069.  
  7070. /*
  7071.  * ":pedit"
  7072.  */
  7073.     static void
  7074. ex_pedit(eap)
  7075.     exarg_T    *eap;
  7076. {
  7077.     win_T    *curwin_save = curwin;
  7078.  
  7079.     g_do_tagpreview = p_pvh;
  7080.     prepare_tagpreview();
  7081.     keep_help_flag = curwin_save->w_buffer->b_help;
  7082.     do_exedit(eap, NULL);
  7083.     keep_help_flag = FALSE;
  7084.     if (curwin != curwin_save && win_valid(curwin_save))
  7085.     {
  7086.     /* Return cursor to where we were */
  7087.     validate_cursor();
  7088.     redraw_later(VALID);
  7089.     win_enter(curwin_save, TRUE);
  7090.     }
  7091.     g_do_tagpreview = 0;
  7092. }
  7093. # endif
  7094.  
  7095. /*
  7096.  * ":stag", ":stselect" and ":stjump".
  7097.  */
  7098.     static void
  7099. ex_stag(eap)
  7100.     exarg_T    *eap;
  7101. {
  7102.     postponed_split = -1;
  7103.     ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
  7104. }
  7105. #endif
  7106.  
  7107. /*
  7108.  * ":tag", ":tselect", ":tjump", ":tnext", etc.
  7109.  */
  7110.     static void
  7111. ex_tag(eap)
  7112.     exarg_T    *eap;
  7113. {
  7114.     ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name);
  7115. }
  7116.  
  7117.     static void
  7118. ex_tag_cmd(eap, name)
  7119.     exarg_T    *eap;
  7120.     char_u    *name;
  7121. {
  7122.     int        cmd;
  7123.  
  7124.     switch (name[1])
  7125.     {
  7126.     case 'j': cmd = DT_JUMP;    /* ":tjump" */
  7127.           break;
  7128.     case 's': cmd = DT_SELECT;    /* ":tselect" */
  7129.           break;
  7130.     case 'p': cmd = DT_PREV;    /* ":tprevious" */
  7131.           break;
  7132.     case 'N': cmd = DT_PREV;    /* ":tNext" */
  7133.           break;
  7134.     case 'n': cmd = DT_NEXT;    /* ":tnext" */
  7135.           break;
  7136.     case 'o': cmd = DT_POP;        /* ":pop" */
  7137.           break;
  7138.     case 'f':            /* ":tfirst" */
  7139.     case 'r': cmd = DT_FIRST;    /* ":trewind" */
  7140.           break;
  7141.     case 'l': cmd = DT_LAST;    /* ":tlast" */
  7142.           break;
  7143.     default:            /* ":tag" */
  7144. #ifdef FEAT_CSCOPE
  7145.           if (p_cst)
  7146.           {
  7147.               do_cstag(eap);
  7148.               return;
  7149.           }
  7150. #endif
  7151.           cmd = DT_TAG;
  7152.           break;
  7153.     }
  7154.  
  7155.     do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
  7156.                               eap->forceit, TRUE);
  7157. }
  7158.  
  7159. #ifdef FEAT_EVAL
  7160.  
  7161.     static void
  7162. ex_if(eap)
  7163.     exarg_T    *eap;
  7164. {
  7165.     int        error;
  7166.     int        skip;
  7167.     int        result;
  7168.     struct condstack    *cstack = eap->cstack;
  7169.  
  7170.     if (cstack->cs_idx == CSTACK_LEN - 1)
  7171.     eap->errmsg = (char_u *)N_(":if nesting too deep");
  7172.     else
  7173.     {
  7174.     ++cstack->cs_idx;
  7175.     cstack->cs_flags[cstack->cs_idx] = 0;
  7176.  
  7177.     /*
  7178.      * Don't do something when there is a surrounding conditional and it
  7179.      * was not active.
  7180.      */
  7181.     skip = (cstack->cs_idx > 0
  7182.         && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
  7183.  
  7184.     result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
  7185.  
  7186.     if (!skip)
  7187.     {
  7188.         if (result)
  7189.         cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
  7190.         if (error)
  7191.         --cstack->cs_idx;
  7192.     }
  7193.     }
  7194. }
  7195.  
  7196. /*
  7197.  * ":endif".
  7198.  */
  7199.     static void
  7200. ex_endif(eap)
  7201.     exarg_T    *eap;
  7202. {
  7203.     did_endif = TRUE;
  7204.     if (eap->cstack->cs_idx < 0
  7205.         || (eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_WHILE))
  7206.     eap->errmsg = (char_u *)N_(":endif without :if");
  7207.     else
  7208.     --eap->cstack->cs_idx;
  7209. }
  7210.  
  7211. /*
  7212.  * ":else" and ":elseif".
  7213.  */
  7214.     static void
  7215. ex_else(eap)
  7216.     exarg_T    *eap;
  7217. {
  7218.     int        error;
  7219.     int        skip;
  7220.     int        result;
  7221.     struct condstack    *cstack = eap->cstack;
  7222.  
  7223.     if (cstack->cs_idx < 0 || (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE))
  7224.     {
  7225.     if (eap->cmdidx == CMD_else)
  7226.         eap->errmsg = (char_u *)N_(":else without :if");
  7227.     else
  7228.         eap->errmsg = (char_u *)N_(":elseif without :if");
  7229.     }
  7230.     else
  7231.     {
  7232.     /*
  7233.      * Don't do something when there is a surrounding conditional and it
  7234.      * was not active.
  7235.      */
  7236.     skip = (cstack->cs_idx > 0
  7237.         && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
  7238.     if (!skip)
  7239.     {
  7240.         /* if the ":if" was TRUE, reset active, otherwise set it */
  7241.         if (cstack->cs_flags[cstack->cs_idx] & CSF_TRUE)
  7242.         {
  7243.         cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
  7244.         skip = TRUE;    /* don't evaluate an ":elseif" */
  7245.         }
  7246.         else
  7247.         cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE;
  7248.     }
  7249.  
  7250.     if (eap->cmdidx == CMD_elseif)
  7251.     {
  7252.         result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
  7253.  
  7254.         if (!skip && (cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))
  7255.         {
  7256.         if (result)
  7257.             cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
  7258.         else
  7259.             cstack->cs_flags[cstack->cs_idx] = 0;
  7260.         if (error)
  7261.             --cstack->cs_idx;
  7262.         }
  7263.     }
  7264.     }
  7265. }
  7266.  
  7267. /*
  7268.  * Handle ":while".
  7269.  */
  7270.     static void
  7271. ex_while(eap)
  7272.     exarg_T    *eap;
  7273. {
  7274.     int        error;
  7275.     int        skip;
  7276.     int        result;
  7277.     struct condstack    *cstack = eap->cstack;
  7278.  
  7279.     if (cstack->cs_idx == CSTACK_LEN - 1)
  7280.     eap->errmsg = (char_u *)N_(":while nesting too deep");
  7281.     else
  7282.     {
  7283.     /*
  7284.      * cs_had_while is set when we have jumped back from the matching
  7285.      * ":endwhile".  When not set, need to init this cstack entry.
  7286.      */
  7287.     if (!cstack->cs_had_while)
  7288.     {
  7289.         ++cstack->cs_idx;
  7290.         ++cstack->cs_whilelevel;
  7291.         cstack->cs_line[cstack->cs_idx] = -1;
  7292.     }
  7293.     cstack->cs_flags[cstack->cs_idx] = CSF_WHILE;
  7294.  
  7295.     /*
  7296.      * Don't do something when there is a surrounding conditional and it
  7297.      * was not active.
  7298.      */
  7299.     skip = (cstack->cs_idx > 0
  7300.         && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
  7301.     result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
  7302.  
  7303.     if (!skip)
  7304.     {
  7305.         if (result && !error)
  7306.         cstack->cs_flags[cstack->cs_idx] |= CSF_ACTIVE | CSF_TRUE;
  7307.         /*
  7308.          * Set cs_had_while flag, so do_cmdline() will set the line
  7309.          * number in cs_line[].
  7310.          */
  7311.         cstack->cs_had_while = TRUE;
  7312.     }
  7313.     }
  7314. }
  7315.  
  7316. /*
  7317.  * ":continue"
  7318.  */
  7319.     static void
  7320. ex_continue(eap)
  7321.     exarg_T    *eap;
  7322. {
  7323.     struct condstack    *cstack = eap->cstack;
  7324.  
  7325.     if (cstack->cs_whilelevel <= 0 || cstack->cs_idx < 0)
  7326.     eap->errmsg = (char_u *)N_(":continue without :while");
  7327.     else
  7328.     {
  7329.     /* Find the matching ":while". */
  7330.     while (cstack->cs_idx > 0
  7331.             && !(cstack->cs_flags[cstack->cs_idx] & CSF_WHILE))
  7332.         --cstack->cs_idx;
  7333.  
  7334.     /*
  7335.      * Set cs_had_continue, so do_cmdline() will jump back to the matching
  7336.      * ":while".
  7337.      */
  7338.     cstack->cs_had_continue = TRUE;        /* let do_cmdline() handle it */
  7339.     }
  7340. }
  7341.  
  7342. /*
  7343.  * ":break"
  7344.  */
  7345.     static void
  7346. ex_break(eap)
  7347.     exarg_T    *eap;
  7348. {
  7349.     int        idx;
  7350.     struct condstack    *cstack = eap->cstack;
  7351.  
  7352.     if (cstack->cs_whilelevel <= 0 || cstack->cs_idx < 0)
  7353.     eap->errmsg = (char_u *)N_(":break without :while");
  7354.     else
  7355.     {
  7356.     /* Find the matching ":while". */
  7357.     for (idx = cstack->cs_idx; idx >= 0; --idx)
  7358.     {
  7359.         cstack->cs_flags[idx] &= ~CSF_ACTIVE;
  7360.         if (cstack->cs_flags[idx] & CSF_WHILE)
  7361.         break;
  7362.     }
  7363.     }
  7364. }
  7365.  
  7366. /*
  7367.  * ":endwhile"
  7368.  */
  7369.     static void
  7370. ex_endwhile(eap)
  7371.     exarg_T    *eap;
  7372. {
  7373.     struct condstack    *cstack = eap->cstack;
  7374.  
  7375.     if (cstack->cs_whilelevel <= 0 || cstack->cs_idx < 0)
  7376.     eap->errmsg = (char_u *)N_(":endwhile without :while");
  7377.     else
  7378.     {
  7379.     if (!(cstack->cs_flags[cstack->cs_idx] & CSF_WHILE))
  7380.     {
  7381.         eap->errmsg = (char_u *)N_(":endwhile without :while");
  7382.         while (cstack->cs_idx >= 0
  7383.             && !(cstack->cs_flags[cstack->cs_idx] & CSF_WHILE))
  7384.         --cstack->cs_idx;
  7385.     }
  7386.     /*
  7387.      * Set cs_had_endwhile, so do_cmdline() will jump back to the matching
  7388.      * ":while".
  7389.      */
  7390.     cstack->cs_had_endwhile = TRUE;
  7391.     }
  7392. }
  7393.  
  7394. /*
  7395.  * ":endfunction" when not after a ":function"
  7396.  */
  7397. /*ARGSUSED*/
  7398.     static void
  7399. ex_endfunction(eap)
  7400.     exarg_T    *eap;
  7401. {
  7402.     EMSG(_("E193: :endfunction not inside a function"));
  7403. }
  7404.  
  7405. /*
  7406.  * Return TRUE if the string "p" looks like a ":while" command.
  7407.  */
  7408.     static int
  7409. has_while_cmd(p)
  7410.     char_u    *p;
  7411. {
  7412.     p = skipwhite(p);
  7413.     while (*p == ':')
  7414.     ++p;
  7415.     p = skipwhite(p);
  7416.     if (p[0] == 'w' && p[1] == 'h')
  7417.     return TRUE;
  7418.     return FALSE;
  7419. }
  7420.  
  7421. #endif /* FEAT_EVAL */
  7422.  
  7423. /*
  7424.  * Evaluate cmdline variables.
  7425.  *
  7426.  * change '%'        to curbuf->b_ffname
  7427.  *      '#'        to curwin->w_altfile
  7428.  *      '<cword>' to word under the cursor
  7429.  *      '<cWORD>' to WORD under the cursor
  7430.  *      '<cfile>' to path name under the cursor
  7431.  *      '<sfile>' to sourced file name
  7432.  *      '<afile>' to file name for autocommand
  7433.  *      '<abuf>'  to buffer number for autocommand
  7434.  *      '<amatch>' to matching name for autocommand
  7435.  *
  7436.  * When an error is detected, "errormsg" is set to a non-NULL pointer (may be
  7437.  * "" for error without a message) and NULL is returned.
  7438.  * Returns an allocated string if a valid match was found.
  7439.  * Returns NULL if no match was found.    "usedlen" then still contains the
  7440.  * number of characters to skip.
  7441.  */
  7442.     char_u *
  7443. eval_vars(src, usedlen, lnump, errormsg, srcstart)
  7444.     char_u    *src;        /* pointer into commandline */
  7445.     int        *usedlen;    /* characters after src that are used */
  7446.     linenr_T    *lnump;        /* line number for :e command, or NULL */
  7447.     char_u    **errormsg;    /* pointer to error message */
  7448.     char_u    *srcstart;    /* beginning of valid memory for src */
  7449. {
  7450.     int        i;
  7451.     char_u    *s;
  7452.     char_u    *result;
  7453.     char_u    *resultbuf = NULL;
  7454.     int        resultlen;
  7455.     buf_T    *buf;
  7456.     int        valid = VALID_HEAD + VALID_PATH;    /* assume valid result */
  7457.     int        spec_idx;
  7458. #ifdef FEAT_MODIFY_FNAME
  7459.     int        skip_mod = FALSE;
  7460. #endif
  7461.     static char *(spec_str[]) =
  7462.     {
  7463.             "%",
  7464. #define SPEC_PERC   0
  7465.             "#",
  7466. #define SPEC_HASH   1
  7467.             "<cword>",        /* cursor word */
  7468. #define SPEC_CWORD  2
  7469.             "<cWORD>",        /* cursor WORD */
  7470. #define SPEC_CCWORD 3
  7471.             "<cfile>",        /* cursor path name */
  7472. #define SPEC_CFILE  4
  7473.             "<sfile>",        /* ":so" file name */
  7474. #define SPEC_SFILE  5
  7475. #ifdef FEAT_AUTOCMD
  7476.             "<afile>",        /* autocommand file name */
  7477. # define SPEC_AFILE 6
  7478.             "<abuf>",        /* autocommand buffer number */
  7479. # define SPEC_ABUF  7
  7480.             "<amatch>",        /* autocommand match name */
  7481. # define SPEC_AMATCH 8
  7482. #endif
  7483. #ifdef FEAT_CLIENTSERVER
  7484.             "<client>"
  7485. # define SPEC_CLIENT 9
  7486. #endif
  7487.         };
  7488. #define SPEC_COUNT  (sizeof(spec_str) / sizeof(char *))
  7489.  
  7490. #if defined(FEAT_AUTOCMD) || defined(FEAT_CLIENTSERVER)
  7491.     char_u    strbuf[30];
  7492. #endif
  7493.  
  7494.     *errormsg = NULL;
  7495.  
  7496.     /*
  7497.      * Check if there is something to do.
  7498.      */
  7499.     for (spec_idx = 0; spec_idx < SPEC_COUNT; ++spec_idx)
  7500.     {
  7501.     *usedlen = (int)STRLEN(spec_str[spec_idx]);
  7502.     if (STRNCMP(src, spec_str[spec_idx], *usedlen) == 0)
  7503.         break;
  7504.     }
  7505.     if (spec_idx == SPEC_COUNT)        /* no match */
  7506.     {
  7507.     *usedlen = 1;
  7508.     return NULL;
  7509.     }
  7510.  
  7511.     /*
  7512.      * Skip when preceded with a backslash "\%" and "\#".
  7513.      * Note: In "\\%" the % is also not recognized!
  7514.      */
  7515.     if (src > srcstart && src[-1] == '\\')
  7516.     {
  7517.     *usedlen = 0;
  7518.     STRCPY(src - 1, src);        /* remove backslash */
  7519.     return NULL;
  7520.     }
  7521.  
  7522.     /*
  7523.      * word or WORD under cursor
  7524.      */
  7525.     if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD)
  7526.     {
  7527.     resultlen = find_ident_under_cursor(&result, spec_idx == SPEC_CWORD ?
  7528.                       (FIND_IDENT|FIND_STRING) : FIND_STRING);
  7529.     if (resultlen == 0)
  7530.     {
  7531.         *errormsg = (char_u *)"";
  7532.         return NULL;
  7533.     }
  7534.     }
  7535.  
  7536.     /*
  7537.      * '#': Alternate file name
  7538.      * '%': Current file name
  7539.      *        File name under the cursor
  7540.      *        File name for autocommand
  7541.      *    and following modifiers
  7542.      */
  7543.     else
  7544.     {
  7545.     switch (spec_idx)
  7546.     {
  7547.     case SPEC_PERC:        /* '%': current file */
  7548.         if (curbuf->b_fname == NULL)
  7549.         {
  7550.             result = (char_u *)"";
  7551.             valid = 0;        /* Must have ":p:h" to be valid */
  7552.         }
  7553.         else
  7554. #ifdef RISCOS
  7555.             /* Always use the full path for RISC OS if possible. */
  7556.             result = curbuf->b_ffname;
  7557.             if (result == NULL)
  7558.             result = curbuf->b_fname;
  7559. #else
  7560.             result = curbuf->b_fname;
  7561. #endif
  7562.         break;
  7563.  
  7564.     case SPEC_HASH:        /* '#' or "#99": alternate file */
  7565.         if (src[1] == '#')  /* "##": the argument list */
  7566.         {
  7567.             result = arg_all();
  7568.             resultbuf = result;
  7569.             *usedlen = 2;
  7570. #ifdef FEAT_MODIFY_FNAME
  7571.             skip_mod = TRUE;
  7572. #endif
  7573.             break;
  7574.         }
  7575.         s = src + 1;
  7576.         i = (int)getdigits(&s);
  7577.         *usedlen = (int)(s - src); /* length of what we expand */
  7578.  
  7579.         buf = buflist_findnr(i);
  7580.         if (buf == NULL)
  7581.         {
  7582.             *errormsg = (char_u *)_("E194: No alternate file name to substitute for '#'");
  7583.             return NULL;
  7584.         }
  7585.         if (lnump != NULL)
  7586.             *lnump = ECMD_LAST;
  7587.         if (buf->b_fname == NULL)
  7588.         {
  7589.             result = (char_u *)"";
  7590.             valid = 0;        /* Must have ":p:h" to be valid */
  7591.         }
  7592.         else
  7593.             result = buf->b_fname;
  7594.         break;
  7595.  
  7596. #ifdef FEAT_SEARCHPATH
  7597.     case SPEC_CFILE:    /* file name under cursor */
  7598.         result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L);
  7599.         if (result == NULL)
  7600.         {
  7601.             *errormsg = (char_u *)"";
  7602.             return NULL;
  7603.         }
  7604.         resultbuf = result;        /* remember allocated string */
  7605.         break;
  7606. #endif
  7607.  
  7608. #ifdef FEAT_AUTOCMD
  7609.     case SPEC_AFILE:    /* file name for autocommand */
  7610.         result = autocmd_fname;
  7611.         if (result == NULL)
  7612.         {
  7613.             *errormsg = (char_u *)_("no autocommand file name to substitute for \"<afile>\"");
  7614.             return NULL;
  7615.         }
  7616.         break;
  7617.  
  7618.     case SPEC_ABUF:        /* buffer number for autocommand */
  7619.         if (autocmd_bufnr <= 0)
  7620.         {
  7621.             *errormsg = (char_u *)_("no autocommand buffer number to substitute for \"<abuf>\"");
  7622.             return NULL;
  7623.         }
  7624.         sprintf((char *)strbuf, "%d", autocmd_bufnr);
  7625.         result = strbuf;
  7626.         break;
  7627.  
  7628.     case SPEC_AMATCH:    /* match name for autocommand */
  7629.         result = autocmd_match;
  7630.         if (result == NULL)
  7631.         {
  7632.             *errormsg = (char_u *)_("no autocommand match name to substitute for \"<amatch>\"");
  7633.             return NULL;
  7634.         }
  7635.         break;
  7636.  
  7637. #endif
  7638.     case SPEC_SFILE:    /* file name for ":so" command */
  7639.         result = sourcing_name;
  7640.         if (result == NULL)
  7641.         {
  7642.             *errormsg = (char_u *)_("no :source file name to substitute for \"<sfile>\"");
  7643.             return NULL;
  7644.         }
  7645.         break;
  7646. #if defined(FEAT_CLIENTSERVER)
  7647.     case SPEC_CLIENT:    /* Source of last submitted input */
  7648.         sprintf((char *)strbuf, "0x%x", (unsigned int)clientWindow);
  7649.         result = strbuf;
  7650.         break;
  7651. #endif
  7652.     }
  7653.  
  7654.     resultlen = (int)STRLEN(result);    /* length of new string */
  7655.     if (src[*usedlen] == '<')    /* remove the file name extension */
  7656.     {
  7657.         ++*usedlen;
  7658. #ifdef RISCOS
  7659.         if ((s = vim_strrchr(result, '/')) != NULL && s >= gettail(result))
  7660. #else
  7661.         if ((s = vim_strrchr(result, '.')) != NULL && s >= gettail(result))
  7662. #endif
  7663.         resultlen = (int)(s - result);
  7664.     }
  7665. #ifdef FEAT_MODIFY_FNAME
  7666.     else if (!skip_mod)
  7667.     {
  7668.         valid |= modify_fname(src, usedlen, &result, &resultbuf,
  7669.                                   &resultlen);
  7670.         if (result == NULL)
  7671.         {
  7672.         *errormsg = (char_u *)"";
  7673.         return NULL;
  7674.         }
  7675.     }
  7676. #endif
  7677.     }
  7678.  
  7679.     if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH)
  7680.     {
  7681.     if (valid != VALID_HEAD + VALID_PATH)
  7682.         /* xgettext:no-c-format */
  7683.         *errormsg = (char_u *)_("Empty file name for '%' or '#', only works with \":p:h\"");
  7684.     else
  7685.         *errormsg = (char_u *)_("Evaluates to an empty string");
  7686.     result = NULL;
  7687.     }
  7688.     else
  7689.     result = vim_strnsave(result, resultlen);
  7690.     vim_free(resultbuf);
  7691.     return result;
  7692. }
  7693.  
  7694. /*
  7695.  * Concatenate all files in the argument list, separated by spaces, and return
  7696.  * it in one allocated string.
  7697.  * Spaces and backslashes in the file names are escaped with a backslash.
  7698.  * Returns NULL when out of memory.
  7699.  */
  7700.     static char_u *
  7701. arg_all()
  7702. {
  7703.     int        len;
  7704.     int        idx;
  7705.     char_u    *retval = NULL;
  7706.     char_u    *p;
  7707.  
  7708.     /*
  7709.      * Do this loop two times:
  7710.      * first time: compute the total length
  7711.      * second time: concatenate the names
  7712.      */
  7713.     for (;;)
  7714.     {
  7715.     len = 0;
  7716.     for (idx = 0; idx < ARGCOUNT; ++idx)
  7717.     {
  7718.         p = alist_name(&ARGLIST[idx]);
  7719.         if (p != NULL)
  7720.         {
  7721.         if (len > 0)
  7722.         {
  7723.             /* insert a space in between names */
  7724.             if (retval != NULL)
  7725.             retval[len] = ' ';
  7726.             ++len;
  7727.         }
  7728.         for ( ; *p != NUL; ++p)
  7729.         {
  7730.             if (*p == ' ' || *p == '\\')
  7731.             {
  7732.             /* insert a backslash */
  7733.             if (retval != NULL)
  7734.                 retval[len] = '\\';
  7735.             ++len;
  7736.             }
  7737.             if (retval != NULL)
  7738.             retval[len] = *p;
  7739.             ++len;
  7740.         }
  7741.         }
  7742.     }
  7743.  
  7744.     /* second time: break here */
  7745.     if (retval != NULL)
  7746.     {
  7747.         retval[len] = NUL;
  7748.         break;
  7749.     }
  7750.  
  7751.     /* allocate memory */
  7752.     retval = alloc(len + 1);
  7753.     if (retval == NULL)
  7754.         break;
  7755.     }
  7756.  
  7757.     return retval;
  7758. }
  7759.  
  7760. #if defined(FEAT_AUTOCMD) || defined(PROTO)
  7761. /*
  7762.  * Expand the <sfile> string in "arg".
  7763.  *
  7764.  * Returns an allocated string, or NULL for any error.
  7765.  */
  7766.     char_u *
  7767. expand_sfile(arg)
  7768.     char_u    *arg;
  7769. {
  7770.     char_u    *errormsg;
  7771.     int        len;
  7772.     char_u    *result;
  7773.     char_u    *newres;
  7774.     char_u    *repl;
  7775.     int        srclen;
  7776.     char_u    *p;
  7777.  
  7778.     result = vim_strsave(arg);
  7779.     if (result == NULL)
  7780.     return NULL;
  7781.  
  7782.     for (p = result; *p; )
  7783.     {
  7784.     if (STRNCMP(p, "<sfile>", 7) != 0)
  7785.         ++p;
  7786.     else
  7787.     {
  7788.         /* replace "<sfile>" with the sourced file name, and do ":" stuff */
  7789.         repl = eval_vars(p, &srclen, NULL, &errormsg, result);
  7790.         if (errormsg != NULL)
  7791.         {
  7792.         if (*errormsg)
  7793.             emsg(errormsg);
  7794.         vim_free(result);
  7795.         return NULL;
  7796.         }
  7797.         if (repl == NULL)        /* no match (cannot happen) */
  7798.         {
  7799.         p += srclen;
  7800.         continue;
  7801.         }
  7802.         len = (int)STRLEN(result) - srclen + (int)STRLEN(repl) + 1;
  7803.         newres = alloc(len);
  7804.         if (newres == NULL)
  7805.         {
  7806.         vim_free(repl);
  7807.         vim_free(result);
  7808.         return NULL;
  7809.         }
  7810.         mch_memmove(newres, result, (size_t)(p - result));
  7811.         STRCPY(newres + (p - result), repl);
  7812.         len = (int)STRLEN(newres);
  7813.         STRCAT(newres, p + srclen);
  7814.         vim_free(repl);
  7815.         vim_free(result);
  7816.         result = newres;
  7817.         p = newres + len;        /* continue after the match */
  7818.     }
  7819.     }
  7820.  
  7821.     return result;
  7822. }
  7823. #endif
  7824.  
  7825. #ifdef FEAT_SESSION
  7826. static int ses_win_rec __ARGS((FILE *fd, frame_T *fr));
  7827. static frame_T *ses_skipframe __ARGS((frame_T *fr));
  7828. static int ses_do_frame __ARGS((frame_T *fr));
  7829. static int ses_do_win __ARGS((win_T *wp));
  7830. static int ses_arglist __ARGS((FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp));
  7831. static int ses_put_fname __ARGS((FILE *fd, char_u *name, unsigned *flagp));
  7832. static int ses_fname __ARGS((FILE *fd, buf_T *buf, unsigned *flagp));
  7833.  
  7834. /*
  7835.  * Write openfile commands for the current buffers to an .exrc file.
  7836.  * Return FAIL on error, OK otherwise.
  7837.  */
  7838.     static int
  7839. makeopens(fd, dirnow)
  7840.     FILE    *fd;
  7841.     char_u    *dirnow;    /* Current directory name */
  7842. {
  7843.     buf_T    *buf;
  7844.     int        only_save_windows = TRUE;
  7845.     int        nr;
  7846.     int        cnr = 1;
  7847.     int        restore_size = TRUE;
  7848.     win_T    *wp;
  7849.     char_u    *sname;
  7850.  
  7851.     if (ssop_flags & SSOP_BUFFERS)
  7852.     only_save_windows = FALSE;        /* Save ALL buffers */
  7853.  
  7854.     /*
  7855.      * Begin by setting the this_session variable, and then other
  7856.      * sessionable variables.
  7857.      */
  7858. #ifdef FEAT_EVAL
  7859.     if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL)
  7860.     return FAIL;
  7861.     if (ssop_flags & SSOP_GLOBALS)
  7862.     if (store_session_globals(fd) == FAIL)
  7863.         return FAIL;
  7864. #endif
  7865.  
  7866.     /*
  7867.      * Close all windows but one.
  7868.      */
  7869.     if (put_line(fd, "silent only") == FAIL)
  7870.     return FAIL;
  7871.  
  7872.     /*
  7873.      * Now a :cd command to the session directory or the current directory
  7874.      */
  7875.     if (ssop_flags & SSOP_SESDIR)
  7876.     {
  7877.     if (put_line(fd, "exe \"cd \" . expand(\"<sfile>:p:h\")") == FAIL)
  7878.         return FAIL;
  7879.     }
  7880.     else if (ssop_flags & SSOP_CURDIR)
  7881.     {
  7882.     sname = home_replace_save(NULL, globaldir != NULL ? globaldir : dirnow);
  7883.     if (sname == NULL
  7884.         || fprintf(fd, "cd %s", sname) < 0 || put_eol(fd) == FAIL)
  7885.         return FAIL;
  7886.     vim_free(sname);
  7887.     }
  7888.  
  7889.     /*
  7890.      * Now save the current files, current buffer first.
  7891.      */
  7892.     if (put_line(fd, "set shortmess=aoO") == FAIL)
  7893.     return FAIL;
  7894.  
  7895.     /* Now put the other buffers into the buffer list */
  7896.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  7897.     {
  7898.     if (!(only_save_windows && buf->b_nwindows == 0)
  7899.         && !(buf->b_help && !(ssop_flags & SSOP_HELP))
  7900.         && buf->b_fname != NULL
  7901.         && buf->b_p_bl)
  7902.     {
  7903.         if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
  7904.                        : buf->b_wininfo->wi_fpos.lnum) < 0
  7905.             || ses_fname(fd, buf, &ssop_flags) == FAIL)
  7906.         return FAIL;
  7907.     }
  7908.     }
  7909.  
  7910.     /* the global argument list */
  7911.     if (ses_arglist(fd, "args", &global_alist.al_ga,
  7912.                 !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL)
  7913.     return FAIL;
  7914.  
  7915.     if (ssop_flags & SSOP_RESIZE)
  7916.     {
  7917.     /* Note: after the restore we still check it worked!*/
  7918.     if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0
  7919.         || put_eol(fd) == FAIL)
  7920.         return FAIL;
  7921.     }
  7922.  
  7923. #ifdef FEAT_GUI
  7924.     if (gui.in_use && (ssop_flags & SSOP_WINPOS))
  7925.     {
  7926.     int    x, y;
  7927.  
  7928.     if (gui_mch_get_winpos(&x, &y) == OK)
  7929.     {
  7930.         /* Note: after the restore we still check it worked!*/
  7931.         if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL)
  7932.         return FAIL;
  7933.     }
  7934.     }
  7935. #endif
  7936.  
  7937.     /*
  7938.      * Save current window layout.
  7939.      */
  7940.     if (put_line(fd, "set splitbelow splitright") == FAIL)
  7941.     return FAIL;
  7942.     if (ses_win_rec(fd, topframe) == FAIL)
  7943.     return FAIL;
  7944.     if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL)
  7945.     return FAIL;
  7946.     if (!p_spr && put_line(fd, "set nosplitright") == FAIL)
  7947.     return FAIL;
  7948.  
  7949.     /*
  7950.      * Check if window sizes can be restored (no windows omitted).
  7951.      * Remember the window number of the current window after restoring.
  7952.      */
  7953.     nr = 0;
  7954.     for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
  7955.     {
  7956.     if (ses_do_win(wp))
  7957.         ++nr;
  7958.     else
  7959.         restore_size = FALSE;
  7960.     if (curwin == wp)
  7961.         cnr = nr;
  7962.     }
  7963.  
  7964.     /* Go to the first window. */
  7965.     if (put_line(fd, IF_EB("normal \027t", "normal " CTRL_W_STR "t")) == FAIL)
  7966.     return FAIL;
  7967.  
  7968.     /*
  7969.      * If more than one window, see if sizes can be restored.
  7970.      * First set 'winheight' and 'winwidth' to 1 to avoid the windows being
  7971.      * resized when moving between windows.
  7972.      */
  7973.     if (put_line(fd, "set winheight=1 winwidth=1") == FAIL)
  7974.     return FAIL;
  7975.     if (nr > 1)
  7976.     {
  7977.     if (restore_size && (ssop_flags & SSOP_WINSIZE))
  7978.     {
  7979.         for (wp = firstwin; wp != NULL; wp = wp->w_next)
  7980.         {
  7981.         if (!ses_do_win(wp))
  7982.             continue;
  7983.  
  7984.         /* restore height when not full height */
  7985.         if (wp->w_height + wp->w_status_height < topframe->fr_height
  7986.             && (fprintf(fd,
  7987.                 "exe 'resize ' . ((&lines * %ld + %ld) / %ld)",
  7988.                 (long)wp->w_height, Rows / 2, Rows) < 0
  7989.                               || put_eol(fd) == FAIL))
  7990.             return FAIL;
  7991.  
  7992.         /* restore width when not full width */
  7993.         if (wp->w_width < Columns && (fprintf(fd,
  7994.             "exe 'vert resize ' . ((&columns * %ld + %ld) / %ld)",
  7995.                 (long)wp->w_width, Columns / 2, Columns) < 0
  7996.                               || put_eol(fd) == FAIL))
  7997.             return FAIL;
  7998.         if (put_line(fd, IF_EB("normal \027w",
  7999.                      "  normal " CTRL_W_STR "w")) == FAIL)
  8000.             return FAIL;
  8001.  
  8002.         }
  8003.     }
  8004.     else
  8005.     {
  8006.         /* Just equalise window sizes */
  8007.         if (put_line(fd, IF_EB("normal \027=", "normal " CTRL_W_STR "="))
  8008.                                       == FAIL)
  8009.         return FAIL;
  8010.     }
  8011.     }
  8012.  
  8013.     /*
  8014.      * Restore the view of the window (options, file, cursor, etc.).
  8015.      */
  8016.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  8017.     {
  8018.     if (!ses_do_win(wp))
  8019.         continue;
  8020.     if (put_view(fd, wp, TRUE, &ssop_flags) == FAIL)
  8021.         return FAIL;
  8022.     if (nr > 1 && put_line(fd, IF_EB("normal \027w",
  8023.                        "normal " CTRL_W_STR "w")) == FAIL)
  8024.         return FAIL;
  8025.     }
  8026.  
  8027.     /*
  8028.      * Restore cursor to the current window if it's not the first one.
  8029.      */
  8030.     if (cnr > 1 && (fprintf(fd, IF_EB("normal %d\027w",
  8031.                      "normal %d" CTRL_W_STR "w"), cnr) < 0
  8032.                               || put_eol(fd) == FAIL))
  8033.     return FAIL;
  8034.  
  8035.     /* Re-apply 'winheight', 'winwidth' and 'shortmess'. */
  8036.     if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s",
  8037.                    p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL)
  8038.     return FAIL;
  8039.  
  8040.     /*
  8041.      * Lastly, execute the x.vim file if it exists.
  8042.      */
  8043.     if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
  8044.         || put_line(fd, "if file_readable(s:sx)") == FAIL
  8045.         || put_line(fd, "  exe \"source \" . s:sx") == FAIL
  8046.         || put_line(fd, "endif") == FAIL)
  8047.     return FAIL;
  8048.  
  8049.     return OK;
  8050. }
  8051.  
  8052. /*
  8053.  * Write commands to "fd" to recursively create windows for frame "fr",
  8054.  * horizontally and vertically split.
  8055.  * After the commands the last window in the frame is the current window.
  8056.  * Returns FAIL when writing the commands to "fd" fails.
  8057.  */
  8058.     static int
  8059. ses_win_rec(fd, fr)
  8060.     FILE    *fd;
  8061.     frame_T    *fr;
  8062. {
  8063.     frame_T    *frc;
  8064.     int        count = 0;
  8065.  
  8066.     if (fr->fr_layout != FR_LEAF)
  8067.     {
  8068.     /* Find first frame that's not skipped and then create a window for
  8069.      * each following one (first frame is already there). */
  8070.     frc = ses_skipframe(fr->fr_child);
  8071.     if (frc != NULL)
  8072.         while ((frc = ses_skipframe(frc->fr_next)) != NULL)
  8073.         {
  8074.         /* Make window as big as possible so that we have lots of room
  8075.          * to split. */
  8076.         if (put_line(fd, IF_EB("normal \027_\027|",
  8077.                  "normal " CTRL_W_STR "_" CTRL_W_STR "|")) == FAIL
  8078.             || put_line(fd, fr->fr_layout == FR_COL
  8079.                         ? "split" : "vsplit") == FAIL)
  8080.             return FAIL;
  8081.         ++count;
  8082.         }
  8083.  
  8084.     /* Go back to the first window. */
  8085.     if (count > 0 && (fprintf(fd, fr->fr_layout == FR_COL
  8086.             ? IF_EB("normal %d\027k", "normal %d" CTRL_W_STR "k")
  8087.             : IF_EB("normal %d\027h", "normal %d" CTRL_W_STR "h"),
  8088.             count) < 0
  8089.                               || put_eol(fd) == FAIL))
  8090.         return FAIL;
  8091.  
  8092.     /* Recursively create frames/windows in each window of this column or
  8093.      * row. */
  8094.     frc = ses_skipframe(fr->fr_child);
  8095.     while (frc != NULL)
  8096.     {
  8097.         ses_win_rec(fd, frc);
  8098.         frc = ses_skipframe(frc->fr_next);
  8099.         /* Go to next window. */
  8100.         if (frc != NULL && put_line(fd, IF_EB("normal \027w",
  8101.                        "normal " CTRL_W_STR "w")) == FAIL)
  8102.         return FAIL;
  8103.     }
  8104.     }
  8105.     return OK;
  8106. }
  8107.  
  8108. /*
  8109.  * Skip frames that don't contain windows we want to save in the Session.
  8110.  * Returns NULL when there none.
  8111.  */
  8112.     static frame_T *
  8113. ses_skipframe(fr)
  8114.     frame_T    *fr;
  8115. {
  8116.     frame_T    *frc;
  8117.  
  8118.     for (frc = fr; frc != NULL; frc = frc->fr_next)
  8119.     if (ses_do_frame(frc))
  8120.         break;
  8121.     return frc;
  8122. }
  8123.  
  8124. /*
  8125.  * Return TRUE if frame "fr" has a window somewhere that we want to save in
  8126.  * the Session.
  8127.  */
  8128.     static int
  8129. ses_do_frame(fr)
  8130.     frame_T    *fr;
  8131. {
  8132.     frame_T    *frc;
  8133.  
  8134.     if (fr->fr_layout == FR_LEAF)
  8135.     return ses_do_win(fr->fr_win);
  8136.     for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next)
  8137.     if (ses_do_frame(frc))
  8138.         return TRUE;
  8139.     return FALSE;
  8140. }
  8141.  
  8142. /*
  8143.  * Return non-zero if window "wp" is to be stored in the Session.
  8144.  */
  8145.     static int
  8146. ses_do_win(wp)
  8147.     win_T    *wp;
  8148. {
  8149.     if (wp->w_buffer->b_fname == NULL
  8150. #ifdef FEAT_QUICKFIX
  8151.         /* When 'buftype' is "nofile" can't restore the window contents. */
  8152.         || bt_nofile(wp->w_buffer)
  8153. #endif
  8154.        )
  8155.     return (ssop_flags & SSOP_BLANK);
  8156.     if (wp->w_buffer->b_help)
  8157.     return (ssop_flags & SSOP_HELP);
  8158.     return TRUE;
  8159. }
  8160.  
  8161. /*
  8162.  * Write commands to "fd" to restore the view of a window.
  8163.  * Caller must make sure 'scrolloff' is zero.
  8164.  */
  8165.     static int
  8166. put_view(fd, wp, add_edit, flagp)
  8167.     FILE    *fd;
  8168.     win_T    *wp;
  8169.     int        add_edit;    /* add ":edit" command to view */
  8170.     unsigned    *flagp;        /* vop_flags or ssop_flags */
  8171. {
  8172.     win_T    *save_curwin;
  8173.     int        f;
  8174.     int        do_cursor;
  8175.  
  8176.     /* Always restore cursor position for ":mksession".  For ":mkview" only
  8177.      * when 'viewoptions' contains "cursor". */
  8178.     do_cursor = (flagp == &ssop_flags || *flagp & SSOP_CURSOR);
  8179.  
  8180.     /*
  8181.      * Local argument list.
  8182.      */
  8183.     if (wp->w_alist == &global_alist)
  8184.     {
  8185.     if (put_line(fd, "argglobal") == FAIL)
  8186.         return FAIL;
  8187.     }
  8188.     else
  8189.     {
  8190.     if (ses_arglist(fd, "arglocal", &wp->w_alist->al_ga,
  8191.             flagp == &vop_flags
  8192.             || !(*flagp & SSOP_CURDIR)
  8193.             || wp->w_localdir != NULL, flagp) == FAIL)
  8194.         return FAIL;
  8195.     }
  8196.  
  8197.     /* Only when part of a session: restore the argument index. */
  8198.     if (wp->w_arg_idx != 0 && flagp == &ssop_flags)
  8199.     {
  8200.     if (fprintf(fd, "%ldnext", (long)wp->w_arg_idx) < 0
  8201.         || put_eol(fd) == FAIL)
  8202.         return FAIL;
  8203.     }
  8204.  
  8205.     if (add_edit)
  8206.     {
  8207.     /*
  8208.      * Load the file.
  8209.      */
  8210.     if (wp->w_buffer->b_ffname != NULL
  8211. #ifdef FEAT_QUICKFIX
  8212.         && !bt_nofile(wp->w_buffer)
  8213. #endif
  8214.         )
  8215.     {
  8216.         /*
  8217.          * Editing a file in this buffer: use ":edit file".
  8218.          * This may have side effects! (e.g., compressed or network file).
  8219.          */
  8220.         if (fputs("edit ", fd) < 0
  8221.             || ses_fname(fd, wp->w_buffer, flagp) == FAIL)
  8222.         return FAIL;
  8223.     }
  8224.     else
  8225.     {
  8226.         /* No file in this buffer, just make it empty. */
  8227.         if (put_line(fd, "enew") == FAIL)
  8228.         return FAIL;
  8229. #ifdef FEAT_QUICKFIX
  8230.         if (wp->w_buffer->b_ffname != NULL)
  8231.         {
  8232.         /* The buffer does have a name, but it's not a file name. */
  8233.         if (fputs("file ", fd) < 0
  8234.             || ses_fname(fd, wp->w_buffer, flagp) == FAIL)
  8235.             return FAIL;
  8236.         }
  8237. #endif
  8238.         do_cursor = FALSE;
  8239.     }
  8240.     }
  8241.  
  8242.     /*
  8243.      * Local mappings and abbreviations.
  8244.      */
  8245.     if ((*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
  8246.                      && makemap(fd, wp->w_buffer) == FAIL)
  8247.     return FAIL;
  8248.  
  8249.     /*
  8250.      * Local options.  Need to go to the window temporarily.
  8251.      * Store only local values when using ":mkview" and when ":mksession" is
  8252.      * used and 'sessionoptions' doesn't include "options".
  8253.      * Some folding options are always stored when "folds" is included,
  8254.      * otherwise the folds would not be restored correctly.
  8255.      */
  8256.     save_curwin = curwin;
  8257.     curwin = wp;
  8258.     curbuf = curwin->w_buffer;
  8259.     if (*flagp & (SSOP_OPTIONS | SSOP_LOCALOPTIONS))
  8260.     f = makeset(fd, OPT_LOCAL,
  8261.                  flagp == &vop_flags || !(*flagp & SSOP_OPTIONS));
  8262. #ifdef FEAT_FOLDING
  8263.     else if (*flagp & SSOP_FOLDS)
  8264.     f = makefoldset(fd);
  8265. #endif
  8266.     else
  8267.     f = OK;
  8268.     curwin = save_curwin;
  8269.     curbuf = curwin->w_buffer;
  8270.     if (f == FAIL)
  8271.     return FAIL;
  8272.  
  8273. #ifdef FEAT_FOLDING
  8274.     /*
  8275.      * Folds.
  8276.      */
  8277.     if (*flagp & SSOP_FOLDS)
  8278.     {
  8279.     if (put_folds(fd, wp) == FAIL)
  8280.         return FAIL;
  8281.     }
  8282. #endif
  8283.  
  8284.     /*
  8285.      * Set the cursor after creating folds, since that moves the cursor.
  8286.      */
  8287.     if (do_cursor)
  8288.     {
  8289.  
  8290.     /* Restore the cursor line in the file and relatively in the
  8291.      * window.  Don't use "G", it changes the jumplist. */
  8292.     if (fprintf(fd, "let s:l = %ld - ((%ld * winheight(0) + %ld) / %ld)",
  8293.             (long)wp->w_cursor.lnum,
  8294.             (long)(wp->w_cursor.lnum - wp->w_topline),
  8295.             (long)wp->w_height / 2, (long)wp->w_height) < 0
  8296.         || put_eol(fd) == FAIL
  8297.         || put_line(fd, "if s:l < 1 | let s:l = 1 | endif") == FAIL
  8298.         || put_line(fd, "exe s:l") == FAIL
  8299.         || put_line(fd, "normal zt") == FAIL
  8300.         || fprintf(fd, "%ld", (long)wp->w_cursor.lnum) < 0
  8301.         || put_eol(fd) == FAIL)
  8302.         return FAIL;
  8303.     /* Restore the cursor column and left offset when not wrapping. */
  8304.     if (wp->w_cursor.col == 0)
  8305.     {
  8306.         if (put_line(fd, "normal 0") == FAIL)
  8307.         return FAIL;
  8308.     }
  8309.     else
  8310.     {
  8311.         if (!wp->w_p_wrap && wp->w_leftcol > 0 && wp->w_width > 0)
  8312.         {
  8313.         if (fprintf(fd,
  8314.               "let s:c = %ld - ((%ld * winwidth(0) + %ld) / %ld)",
  8315.                 (long)wp->w_cursor.col,
  8316.                 (long)(wp->w_cursor.col - wp->w_leftcol),
  8317.                 (long)wp->w_width / 2, (long)wp->w_width) < 0
  8318.             || put_eol(fd) == FAIL
  8319.             || put_line(fd, "if s:c > 0") == FAIL
  8320.             || fprintf(fd,
  8321.                 "  exe 'normal 0' . s:c . 'lzs' . (%ld - s:c) . 'l'",
  8322.                 (long)wp->w_cursor.col) < 0
  8323.             || put_eol(fd) == FAIL
  8324.             || put_line(fd, "else") == FAIL
  8325.             || fprintf(fd, "  normal 0%dl", wp->w_cursor.col) < 0
  8326.             || put_eol(fd) == FAIL
  8327.             || put_line(fd, "endif") == FAIL)
  8328.             return FAIL;
  8329.         }
  8330.         else
  8331.         {
  8332.         if (fprintf(fd, "normal 0%dl", wp->w_cursor.col) < 0
  8333.             || put_eol(fd) == FAIL)
  8334.             return FAIL;
  8335.         }
  8336.     }
  8337.     }
  8338.  
  8339.     /*
  8340.      * Local directory.
  8341.      */
  8342.     if (wp->w_localdir != NULL)
  8343.     {
  8344.     if (fputs("lcd ", fd) < 0
  8345.         || ses_put_fname(fd, wp->w_localdir, flagp) == FAIL
  8346.         || put_eol(fd) == FAIL)
  8347.         return FAIL;
  8348.     }
  8349.  
  8350.     return OK;
  8351. }
  8352.  
  8353. /*
  8354.  * Write an argument list to the session file.
  8355.  * Returns FAIL if writing fails.
  8356.  */
  8357.     static int
  8358. ses_arglist(fd, cmd, gap, fullname, flagp)
  8359.     FILE    *fd;
  8360.     char    *cmd;
  8361.     garray_T    *gap;
  8362.     int        fullname;    /* TRUE: use full path name */
  8363.     unsigned    *flagp;
  8364. {
  8365.     int        i;
  8366.     char_u    buf[MAXPATHL];
  8367.     char_u    *s;
  8368.  
  8369.     if (gap->ga_len == 0)
  8370.     return put_line(fd, "silent! argdel *");
  8371.     if (fputs(cmd, fd) < 0)
  8372.     return FAIL;
  8373.     for (i = 0; i < gap->ga_len; ++i)
  8374.     {
  8375.     /* NULL file names are skipped (only happens when out of memory). */
  8376.     s = alist_name(&((aentry_T *)gap->ga_data)[i]);
  8377.     if (s != NULL)
  8378.     {
  8379.         if (fullname)
  8380.         {
  8381.         (void)vim_FullName(s, buf, MAXPATHL, FALSE);
  8382.         s = buf;
  8383.         }
  8384.         if (fputs(" ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL)
  8385.         return FAIL;
  8386.     }
  8387.     }
  8388.     return put_eol(fd);
  8389. }
  8390.  
  8391. /*
  8392.  * Write a buffer name to the session file.
  8393.  * Also ends the line.
  8394.  * Returns FAIL if writing fails.
  8395.  */
  8396.     static int
  8397. ses_fname(fd, buf, flagp)
  8398.     FILE    *fd;
  8399.     buf_T    *buf;
  8400.     unsigned    *flagp;
  8401. {
  8402.     char_u    *name;
  8403.  
  8404.     /* Use the short file name if the current directory is known at the time
  8405.      * the session file will be sourced.  Don't do this for ":mkview", we
  8406.      * don't know the current directory. */
  8407.     if (buf->b_sfname != NULL
  8408.         && flagp == &ssop_flags
  8409.         && (ssop_flags & (SSOP_CURDIR | SSOP_SESDIR)))
  8410.     name = buf->b_sfname;
  8411.     else
  8412.     name = buf->b_ffname;
  8413.     if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL)
  8414.     return FAIL;
  8415.     return OK;
  8416. }
  8417.  
  8418. /*
  8419.  * Write a file name to the session file.
  8420.  * Takes care of the "slash" option in 'sessionoptions'.
  8421.  * Returns FAIL if writing fails.
  8422.  */
  8423.     static int
  8424. ses_put_fname(fd, name, flagp)
  8425.     FILE    *fd;
  8426.     char_u    *name;
  8427.     unsigned    *flagp;
  8428. {
  8429.     char_u    *sname;
  8430.     int        retval = OK;
  8431.     int        c;
  8432.  
  8433.     sname = home_replace_save(NULL, name);
  8434.     if (sname != NULL)
  8435.     name = sname;
  8436.     if (*flagp & SSOP_SLASH)
  8437.     {
  8438.     while (*name)
  8439.     {
  8440.         c = *name++;
  8441.         if (c == '\\')
  8442.         c = '/';
  8443.         if (putc(c, fd) != c)
  8444.         retval = FAIL;
  8445.     }
  8446.     }
  8447.     else if (fputs((char *)name, fd) < 0)
  8448.     retval = FAIL;
  8449.     vim_free(sname);
  8450.     return retval;
  8451. }
  8452.  
  8453. /*
  8454.  * ":loadview [nr]"
  8455.  */
  8456.     static void
  8457. ex_loadview(eap)
  8458.     exarg_T    *eap;
  8459. {
  8460.     char_u    *fname;
  8461.  
  8462.     fname = get_view_file(*eap->arg);
  8463.     if (fname != NULL)
  8464.     {
  8465.     do_source(fname, FALSE, FALSE);
  8466.     vim_free(fname);
  8467.     }
  8468. }
  8469.  
  8470. /*
  8471.  * Get the name of the view file for the current buffer.
  8472.  */
  8473.     static char_u *
  8474. get_view_file(c)
  8475.     int        c;
  8476. {
  8477.     int        len = 0;
  8478.     char_u    *p, *s;
  8479.     char_u    *retval;
  8480.     char_u    *sname;
  8481.  
  8482.     if (curbuf->b_ffname == NULL)
  8483.     {
  8484.     EMSG(_(e_noname));
  8485.     return NULL;
  8486.     }
  8487.     sname = home_replace_save(NULL, curbuf->b_ffname);
  8488.     if (sname == NULL)
  8489.     return NULL;
  8490.  
  8491.     /*
  8492.      * We want a file name without separators, because we're not going to make
  8493.      * a directory.
  8494.      * "normal" path separator    -> "=+"
  8495.      * "="            -> "=="
  8496.      * ":" path separator    -> "=-"
  8497.      */
  8498.     for (p = sname; *p; ++p)
  8499.     if (*p == '=' || vim_ispathsep(*p))
  8500.         ++len;
  8501.     retval = alloc((unsigned)(STRLEN(sname) + len + STRLEN(p_vdir) + 9));
  8502.     if (retval != NULL)
  8503.     {
  8504.     STRCPY(retval, p_vdir);
  8505.     add_pathsep(retval);
  8506.     s = retval + STRLEN(retval);
  8507.     for (p = sname; *p; ++p)
  8508.     {
  8509.         if (*p == '=')
  8510.         {
  8511.         *s++ = '=';
  8512.         *s++ = '=';
  8513.         }
  8514.         else if (vim_ispathsep(*p))
  8515.         {
  8516.         *s++ = '=';
  8517. #ifdef MACOS_CLASSIC /* TODO: Is it also needed for MACOS_X? (Dany) */
  8518.         *s++ = '+';
  8519. #else
  8520. # if defined(BACKSLASH_IN_FILENAME) || defined(AMIGA) || defined(RISCOS) \
  8521.     || defined(VMS)
  8522.         if (*p == ':')
  8523.             *s++ = '-';
  8524.         else
  8525. # endif
  8526.             *s++ = '+';
  8527. #endif
  8528.         }
  8529.         else
  8530.         *s++ = *p;
  8531.     }
  8532.     *s++ = '=';
  8533.     *s++ = c;
  8534.     STRCPY(s, ".vim");
  8535.     }
  8536.  
  8537.     vim_free(sname);
  8538.     return retval;
  8539. }
  8540.  
  8541. #endif /* FEAT_SESSION */
  8542.  
  8543. /*
  8544.  * Write end-of-line character(s) for ":mkexrc", ":mkvimrc" and ":mksession".
  8545.  * Return FAIL for a write error.
  8546.  */
  8547.     int
  8548. put_eol(fd)
  8549.     FILE    *fd;
  8550. {
  8551.     if (
  8552. #ifdef USE_CRNL
  8553.         (
  8554. # ifdef MKSESSION_NL
  8555.          !mksession_nl &&
  8556. # endif
  8557.          (putc('\r', fd) < 0)) ||
  8558. #endif
  8559.         (putc('\n', fd) < 0))
  8560.     return FAIL;
  8561.     return OK;
  8562. }
  8563.  
  8564. /*
  8565.  * Write a line to "fd".
  8566.  * Return FAIL for a write error.
  8567.  */
  8568.     int
  8569. put_line(fd, s)
  8570.     FILE    *fd;
  8571.     char    *s;
  8572. {
  8573.     if (fputs(s, fd) < 0 || put_eol(fd) == FAIL)
  8574.     return FAIL;
  8575.     return OK;
  8576. }
  8577.  
  8578. #ifdef FEAT_VIMINFO
  8579. /*
  8580.  * ":rviminfo" and ":wviminfo".
  8581.  */
  8582.     static void
  8583. ex_viminfo(eap)
  8584.     exarg_T    *eap;
  8585. {
  8586.     char_u    *save_viminfo;
  8587.  
  8588.     save_viminfo = p_viminfo;
  8589.     if (*p_viminfo == NUL)
  8590.     p_viminfo = (char_u *)"'100";
  8591.     if (eap->cmdidx == CMD_rviminfo)
  8592.     {
  8593.     if (read_viminfo(eap->arg, TRUE, TRUE, eap->forceit) == FAIL)
  8594.         EMSG(_("E195: Cannot open viminfo file for reading"));
  8595.     }
  8596.     else
  8597.     write_viminfo(eap->arg, eap->forceit);
  8598.     p_viminfo = save_viminfo;
  8599. }
  8600. #endif
  8601.  
  8602. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
  8603.     void
  8604. dialog_msg(buff, format, fname)
  8605.     char_u    *buff;
  8606.     char    *format;
  8607.     char_u    *fname;
  8608. {
  8609.     int        len;
  8610.  
  8611.     if (fname == NULL)
  8612.     fname = (char_u *)_("Untitled");
  8613.     len = (int)STRLEN(format) + (int)STRLEN(fname);
  8614.     if (len >= IOSIZE)
  8615.     sprintf((char *)buff, format, (int)(IOSIZE - STRLEN(format)), fname);
  8616.     else
  8617.     sprintf((char *)buff, format, (int)STRLEN(fname), fname);
  8618. }
  8619. #endif
  8620.  
  8621. /*
  8622.  * ":behave {mswin,xterm}"
  8623.  */
  8624.     static void
  8625. ex_behave(eap)
  8626.     exarg_T    *eap;
  8627. {
  8628.     if (STRCMP(eap->arg, "mswin") == 0)
  8629.     {
  8630.     set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0);
  8631.     set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0);
  8632.     set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0);
  8633.     set_option_value((char_u *)"keymodel", 0L,
  8634.                          (char_u *)"startsel,stopsel", 0);
  8635.     }
  8636.     else if (STRCMP(eap->arg, "xterm") == 0)
  8637.     {
  8638.     set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0);
  8639.     set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0);
  8640.     set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0);
  8641.     set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0);
  8642.     }
  8643.     else
  8644.     EMSG2(_(e_invarg2), eap->arg);
  8645. }
  8646.  
  8647. #ifdef FEAT_AUTOCMD
  8648. static int filetype_detect = FALSE;
  8649. static int filetype_plugin = FALSE;
  8650. static int filetype_indent = FALSE;
  8651.  
  8652. /*
  8653.  * ":filetype [plugin] [indent] {on,off,detect}"
  8654.  * on: Load the filetype.vim file to install autocommands for file types.
  8655.  * off: Load the ftoff.vim file to remove all autocommands for file types.
  8656.  * plugin on: load filetype.vim and ftplugin.vim
  8657.  * plugin off: load ftplugof.vim
  8658.  * indent on: load filetype.vim and indent.vim
  8659.  * indent off: load indoff.vim
  8660.  */
  8661.     static void
  8662. ex_filetype(eap)
  8663.     exarg_T    *eap;
  8664. {
  8665.     char_u    *arg = eap->arg;
  8666.     int        plugin = FALSE;
  8667.     int        indent = FALSE;
  8668.  
  8669.     if (*eap->arg == NUL)
  8670.     {
  8671.     /* Print current status. */
  8672.     smsg((char_u *)"filetype detection:%s  plugin:%s  indent:%s",
  8673.         filetype_detect ? "ON" : "OFF",
  8674.         filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF",
  8675.         filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF");
  8676.     return;
  8677.     }
  8678.  
  8679.     /* Accept "plugin" and "indent" in any order. */
  8680.     for (;;)
  8681.     {
  8682.     if (STRNCMP(arg, "plugin", 6) == 0)
  8683.     {
  8684.         plugin = TRUE;
  8685.         arg = skipwhite(arg + 6);
  8686.         continue;
  8687.     }
  8688.     if (STRNCMP(arg, "indent", 6) == 0)
  8689.     {
  8690.         indent = TRUE;
  8691.         arg = skipwhite(arg + 6);
  8692.         continue;
  8693.     }
  8694.     break;
  8695.     }
  8696.     if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0)
  8697.     {
  8698.     if (*arg == 'o' || !filetype_detect)
  8699.     {
  8700.         cmd_runtime((char_u *)FILETYPE_FILE, TRUE);
  8701.         filetype_detect = TRUE;
  8702.         if (plugin)
  8703.         {
  8704.         cmd_runtime((char_u *)FTPLUGIN_FILE, TRUE);
  8705.         filetype_plugin = TRUE;
  8706.         }
  8707.         if (indent)
  8708.         {
  8709.         cmd_runtime((char_u *)INDENT_FILE, TRUE);
  8710.         filetype_indent = TRUE;
  8711.         }
  8712.     }
  8713.     if (*arg == 'd')
  8714.     {
  8715.         (void)do_doautocmd((char_u *)"filetypedetect BufRead", TRUE);
  8716.         do_modelines();
  8717.     }
  8718.     }
  8719.     else if (STRCMP(arg, "off") == 0)
  8720.     {
  8721.     if (plugin || indent)
  8722.     {
  8723.         if (plugin)
  8724.         {
  8725.         cmd_runtime((char_u *)FTPLUGOF_FILE, TRUE);
  8726.         filetype_plugin = FALSE;
  8727.         }
  8728.         if (indent)
  8729.         {
  8730.         cmd_runtime((char_u *)INDOFF_FILE, TRUE);
  8731.         filetype_indent = FALSE;
  8732.         }
  8733.     }
  8734.     else
  8735.     {
  8736.         cmd_runtime((char_u *)FTOFF_FILE, TRUE);
  8737.         filetype_detect = FALSE;
  8738.     }
  8739.     }
  8740.     else
  8741.     EMSG2(_(e_invarg2), arg);
  8742. }
  8743.  
  8744. /*
  8745.  * ":setfiletype {name}"
  8746.  */
  8747.     static void
  8748. ex_setfiletype(eap)
  8749.     exarg_T    *eap;
  8750. {
  8751.     if (!did_filetype)
  8752.     set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL);
  8753. }
  8754. #endif
  8755.  
  8756. /*ARGSUSED*/
  8757.     static void
  8758. ex_digraphs(eap)
  8759.     exarg_T    *eap;
  8760. {
  8761. #ifdef FEAT_DIGRAPHS
  8762.     if (*eap->arg != NUL)
  8763.     putdigraph(eap->arg);
  8764.     else
  8765.     listdigraphs();
  8766. #else
  8767.     EMSG(_("E196: No digraphs in this version"));
  8768. #endif
  8769. }
  8770.  
  8771.     static void
  8772. ex_set(eap)
  8773.     exarg_T    *eap;
  8774. {
  8775.     int        flags = 0;
  8776.  
  8777.     if (eap->cmdidx == CMD_setlocal)
  8778.     flags = OPT_LOCAL;
  8779.     else if (eap->cmdidx == CMD_setglobal)
  8780.     flags = OPT_GLOBAL;
  8781. #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) && defined(FEAT_BROWSE)
  8782.     if (cmdmod.browse && flags == 0)
  8783.     ex_options(eap);
  8784.     else
  8785. #endif
  8786.     (void)do_set(eap->arg, flags);
  8787. }
  8788.  
  8789. #ifdef FEAT_SEARCH_EXTRA
  8790. /*
  8791.  * ":nohlsearch"
  8792.  */
  8793. /*ARGSUSED*/
  8794.     static void
  8795. ex_nohlsearch(eap)
  8796.     exarg_T    *eap;
  8797. {
  8798.     no_hlsearch = TRUE;
  8799.     redraw_all_later(NOT_VALID);
  8800. }
  8801.  
  8802. /*
  8803.  * ":match {group} {pattern}"
  8804.  * Sets nextcmd to the start of the next command, if any.  Also called when
  8805.  * skipping commands to find the next command.
  8806.  */
  8807.     static void
  8808. ex_match(eap)
  8809.     exarg_T    *eap;
  8810. {
  8811.     char_u    *p;
  8812.     char_u    *end;
  8813.     int        c;
  8814.  
  8815.     /* First clear any old pattern. */
  8816.     if (!eap->skip)
  8817.     {
  8818.     vim_free(curwin->w_match.regprog);
  8819.     curwin->w_match.regprog = NULL;
  8820.     redraw_later(NOT_VALID);    /* always need a redraw */
  8821.     }
  8822.  
  8823.     if (ends_excmd(*eap->arg))
  8824.     end = eap->arg;
  8825.     else if ((STRNICMP(eap->arg, "none", 4) == 0
  8826.         && (vim_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4]))))
  8827.     end = eap->arg + 4;
  8828.     else
  8829.     {
  8830.     p = skiptowhite(eap->arg);
  8831.     if (!eap->skip)
  8832.     {
  8833.         curwin->w_match_id = syn_namen2id(eap->arg, (int)(p - eap->arg));
  8834.         if (curwin->w_match_id == 0)
  8835.         {
  8836.         EMSG2(_(e_nogroup), eap->arg);
  8837.         return;
  8838.         }
  8839.     }
  8840.     p = skipwhite(p);
  8841.     if (*p == NUL)
  8842.     {
  8843.         EMSG2(_(e_invarg2), eap->arg);
  8844.         return;
  8845.     }
  8846.     end = skip_regexp(p + 1, *p, TRUE);
  8847.     if (!eap->skip)
  8848.     {
  8849.         c = *end;
  8850.         *end = NUL;
  8851.         curwin->w_match.regprog = vim_regcomp(p + 1, TRUE);
  8852.         *end = c;
  8853.         if (curwin->w_match.regprog == NULL)
  8854.         {
  8855.         EMSG2(_(e_invarg2), p);
  8856.         return;
  8857.         }
  8858.     }
  8859.     }
  8860.     eap->nextcmd = find_nextcmd(end);
  8861. }
  8862. #endif
  8863.  
  8864. #ifdef FEAT_CRYPT
  8865. /*
  8866.  * ":X": Get crypt key
  8867.  */
  8868. /*ARGSUSED*/
  8869.     static void
  8870. ex_X(eap)
  8871.     exarg_T    *eap;
  8872. {
  8873.     (void)get_crypt_key(TRUE, TRUE);
  8874. }
  8875. #endif
  8876.  
  8877. #ifdef FEAT_FOLDING
  8878.     static void
  8879. ex_fold(eap)
  8880.     exarg_T    *eap;
  8881. {
  8882.     if (foldManualAllowed(TRUE))
  8883.     foldCreate(eap->line1, eap->line2);
  8884. }
  8885.  
  8886.     static void
  8887. ex_foldopen(eap)
  8888.     exarg_T    *eap;
  8889. {
  8890.     opFoldRange(eap->line1, eap->line2, eap->cmdidx == CMD_foldopen,
  8891.                              eap->forceit, FALSE);
  8892. }
  8893.  
  8894.     static void
  8895. ex_folddo(eap)
  8896.     exarg_T    *eap;
  8897. {
  8898.     linenr_T    lnum;
  8899.  
  8900.     /* First set the marks for all lines closed/open. */
  8901.     for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
  8902.     if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed))
  8903.         ml_setmarked(lnum);
  8904.  
  8905.     /* Execute the command on the marked lines. */
  8906.     global_exe(eap->arg);
  8907.     ml_clearmarked();       /* clear rest of the marks */
  8908. }
  8909. #endif
  8910.